JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Follow publication

A Guide to JavaScript Callbacks and Promises

Understand JavaScript callbacks and promises.

Photo by Oskar Yildiz on Unsplash

A little bit about JavaScript

JavaScript is a scripting language. It can be written right in the HTML portion of a web page and runs automatically as the page loads.

JavaScript Engines

  1. V8 — in Chrome and Opera
  2. SpiderMonkey — in Firefox
  3. Chakra for IE
  4. ChakraCore for Microsoft Edge
  5. Nitro and SquirrelFish for Safari

What JavaScript can do?

JavaScript can do anything possibly any other programming language can do. But, “its capabilities greatly depend on the environment in which it’s running.

Client-Side

  1. Add new HTML to the page, change the existing content, modify styles.
  2. React to user actions, run on mouse clicks, pointer movements, key presses.
  3. Send requests over the network to remote servers, download and upload files.
  4. Get and set cookies, ask questions to the visitor, show messages.
  5. Remember the data on the client-side (“local storage”).

Server-Side

  1. Read/write files.
  2. Perform network requests.
  3. Create APIs.

What is a Callback? Or why do we need Callbacks?

JavaScript runs code sequentially in top-down order. However, there are some cases that code runs (or must run) after something else happens and also not sequentially. This is called asynchronous programming.

Example:-

  1. Fetch data for DOM manipulation
  2. Get results after complex mathematical calculations

JavaScript is Single Thread Programing Language

Single Thread vs Multi Thread ( IMG 1 )

How Callback Works

Callback ( IMG 2 )

Promise

Promises allow us to wait on certain code to finish execution prior to running the next bit of code.

Difference with Callback

The difference between the two is when using the callback approach, we’d normally just pass a callback into a function that would then get called upon completion in order to get the result of something. In Promises, however, you attach callbacks on the returned Promise object.

Callback Hell

  1. It was getting harder to read (The code was beginning to move in two directions — top to bottom, then left to right).
  2. It was getting harder to manage.
  3. It wasn’t clear what was happening as the code was being nested deeper.
  4. We would always have to make sure we didn’t accidentally declare variables with the same names that were already declared in the outer scopes (this is called shadowing).
  5. We had to account for three different errors at three different locations.
  6. We had to even rename each error to ensure that we don’t shadow the error above it. If we ended up doing additional requests in this train of operations, we’d have to find additional variables names that don’t end up clashing with the errors in the scopes above.

Promise States

  • Pending — Asynchronous operation has not completed yet
  • Fulfilled — Operation has completed, and the Promise has a value
  • Rejected — Operation has completed with an error or failure.

Promise Chaining

Promise chaining becomes absolutely useful when we need to execute a chain of asynchronous tasks.

Promise Methods

  1. Promise.all
  2. Promise.race
  3. Promise.allSettled
  4. Promise.any

Promise.all

When you want to accumulate a batch of asynchronous operations and eventually receive each of their values as an array, one of the promise methods that satisfy this goal is Promise.all.

const promise1 = new Promise((resolve) => {resolve([‘apple’, ‘orange’]);});const promise2 = new Promise((resolve) => {resolve([‘grape’, ‘banana’]);});let fruitsArray = [];Promise.all([promise1, promise2]).then(([basket1, basket2]) => {basket1.forEach((fruit) => {fruitsArray.push(fruit);});basket2.forEach((fruit) => {fruitsArray.push(fruit);});console.log(fruitsArray);}).catch((error) => { console.log(error) });

Promise.race

This method returns a promise that either fulfills or rejects whenever one of the promises in an iterable resolves or rejects with either the value or the reason from that promise.

const promise1 = new Promise((resolve) => {setTimeout(() => {resolve(‘some result’)}, 200)})const promise2 = new Promise((resolve, reject) => {reject(new Error(‘some promise2 error’))})Promise.race([promise1, promise2]).then((result) => {console.log(result)}).catch((error) => {console.error(error)})

Promise.allSettled

The Promise.allSettled method ultimately somewhat resembles Promise.all in sharing a similar goal except instead of immediately rejecting into an error when one of the promises fails, Promise.allSettled will return a promise that eventually always resolves after all of the given promises have either resolved or rejected, accumulating the results into an array where each item represents the result of their promise operation.

const add = (num1, num2) => new Promise((resolve) => resolve(num1 + num2))const multiply = (num1, num2) => new Promise((resolve) => resolve(num1 * num2))const fail = (num1) =>new Promise((resolve, reject) =>setTimeout(() => reject(new Error(‘You, my friend, were too late’)), 200),)const fail2 = (num1) =>new Promise((resolve, reject) =>setTimeout(() => reject(new Error(‘Being late is never a good habit’)),100,),)const promises = [add(2, 4), multiply(5, 5), fail(‘hi’), fail2(‘hello’)]Promise.allSettled(promises).then((result) => {console.log(result)}).catch((error) => {console.error(error)})

Promise.any

The result of Promise.any becomes the value of the promise that resolved.

const resolved = (num1, num2) => return new Promise((resolve) => resolve(num1 + num2))const rejected = () =>return new Promise((resolve, reject) =>setTimeout(() => reject(new Error(‘You, my friend, were too late’)), 200),)const promises = [rejected(), rejected(), resolved(1, 2), rejected(), rejected(), rejected()]
Promise.any(promises)
.then((result) => {console.log(result) // result: 4}).catch((error) => {console.error(error)})

Custom Promise

Sample code to demonstrate how a promise works.

var CustomPromise = function (callback) {
this.then = function (resolver, rejector) {
// sucsuss metod
callback(resolver);
}
}
function demopromise() {
return new CustomPromise(function (resolve, reject) {
setTimeout(function () {
resolve(“This is resolved data”);
}, 3000)
})
}
demopromise().then(function (resolvedData) {
console.log(resolvedData);
})

Summary

  • What is JavaScript?
  • JavaScript Engines.
  • What JavaScript can do.
  • What is a callback?
  • Why do we need callbacks?
  • What is single thread programming?
  • What is multi-thread programming?
  • How callback works.
  • Advantages of promise over callback.
  • Promise methods.
  • Creating our own promise.

More content at plainenglish.io

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Written by Lijoy C George

Enthusiastic about Technology and Computing

Responses (1)

Write a response