Promises In JavaScript: A Complete Guide

Richelle John
3 min readJul 26, 2024

--

An object standing for the ultimate success or failure of an asynchronous activity is a promise. This tutorial will discuss consumption of returned promises first, then go on to discuss how to generate them as most individuals are consumers of already-made promises.

Promises In JavaScript

A promise is essentially a returned object onto which you attach callbacks rather than providing callbacks into a method. Imagine a method, createAudioFileAsync(), which asynchronously produces a sound file given a configuration record and two callback functions: one invoked if the audio file is successfully generated, and the other called should an error arise.

The following code employs createAudioFileAsync():

function successCallback(result) {
console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);

You would connect your callbacks to createAudioFileAsync() instead of rewriting it to fulfill a promise:

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

This conference offers several benefits. We will look at every one.

Chaining

Executing two or more asynchronous actions back to back is a typical necessity whereby each succeeding operation starts after the preceding operation succeeds, with the result from the previous step. Doing numerous asynchronous actions in a succession in the past would cause the traditional callback hell:

doSomething(function (result) {
doSomethingElse(result, function (newResult) {
doThirdThing(newResult, function (finalResult) {
console.log(`Got the final result: ${finalResult}`);
}, failureCallback);
}, failureCallback);
}, failureCallback);

Promises help us to fulfill this by means of a promise chain. Promises have fantastic API design since callbacks attached to the delivered promise object rather than being handed into a method.

The secret is the then() method generates a fresh promise distinct from the original:

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);

Error handling

You might remember seeing failure callback three times in the pyramid of doom previously, contrasted to only once at the promise chain’s end:

doSomething()
.then((result) => doSomethingElse(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);

Should there be an exception, the browser will search onRejected or for catch() handlers along the chain. This is rather closely modeled after synchronous code operation:

try {
const result = syncDoSomething();
const newResult = syncDoSomethingElse(result);
const finalResult = syncDoThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch (error) {
failureCallback(error);
}

This symmetry with asynchronous programming ends with the async/await syntax:

async function foo() {
try {
const result = await doSomething();
const newResult = await doSomethingElse(result);
const finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch (error) {
failureCallback(error);
}
}

Task queues vs. microtasks

SetTimeout() callbacks are treated as task queues; promise callbacks are handled as microtasks.

const promise = new Promise((resolve, reject) => {
console.log("Promise callback");
resolve();
}).then((result) => {
console.log("Promise callback (.then)");
});

setTimeout(() => {
console.log("event-loop cycle: Promise (fulfilled)", promise);
}, 0);

console.log("Promise (pending)", promise);

The above codes will produce:

Promise callback
Promise (pending) Promise {<pending>}
Promise callback (.then)
event-loop cycle: Promise (fulfilled) Promise {<fulfilled>}

When responsibilities and promises cross paths

Using a microtask to verify status or balance out your promises might help you if you find yourself in circumstances whereby your promises and tasks — such as those arising from events or callbacks — are firing in erratic patterns.

See the microtask documentation to learn more about how to use queueMicrotask() to enqueue a function as a microtask should you believe microtasks might help address this problem.

Read More

--

--

Richelle John
Richelle John

Written by Richelle John

With over five years' experience in leading marketing initiatives across Europe and the US, I am a digital marketing expert. Visit Here https://bit.ly/3Wsauvr

No responses yet