What is chaining Promise in JavaScript?
Chaining is an important aspect of programming, especially functional programming. As such JavaScript provides means to chain functions as well as promises. Though promises are special JavaScript objects that are either resolved or rejected, we can chain different promises such that when one promise is resolved, the next promise is done.
One of the key features of JavaScript is the ability to chain promises together, which can make code more readable and maintainable. Chaining promises is a technique that allows developers to chain multiple promises together in a sequence, where the output of one promise becomes the input of the next promise.
In real-life development scenarios, chaining promises can be used to create a sequence of asynchronous operations on a single piece of data. For example, a developer might want to retrieve some data from a remote server, process the retrieved data, and then save the processed data to local storage.
Different methods to chain Promises in JavaScript
- Using
.then()
: You can use the.then()
method to chain promises together. The.then()
method returns a new promise that is resolved with the value returned by the callback function. - Using
.catch()
: You can use the.catch()
method to handle rejected promises. The.catch()
method returns a new promise that is rejected with the value returned by the callback function. - Using
async/await
: You can use theasync/await
syntax to chain promises together. Theawait
keyword can be used to wait for a promise to resolve before moving on to the next line of code. - Using
Promise.all()
: You can use thePromise.all()
method to run multiple promises in parallel and wait for all of them to resolve. The method returns a new promise that is resolved with an array of the resolved values of the input promises in the same order as they were passed.
Chaining Promises
Promises are a way of handling async operations in JavaScript, they are essentially objects that represent the eventual completion or failure of an async operation. The main methods that are used to chain promises are then()
and catch()
.
Before we go into some examples, we use the then()
method to attach a callback function that will be called when a promise is resolved. In addition, we use the catch()
method to attach a function that will be called when the promise is rejected.
Understanding the then()
method
So for us to chain promises sequentially, we can connect different then()
with their corresponding callback functions in the order we want the chain to happen. Let’s illustrate with a simple example of how we can make use of the then()
method. Here, we fetch the user.json
which contains user details, and then use the then()
method to chain promises that will form the response. Afterwards, if the previous promise is resolved, another then()
method is used to log the parsed JSON. Each then()
will be called in sequence if the promise is solved.
fetch("user.json")
.then((response) => response.json())
.then((data) => console.log(data));
Output
Understanding the catch()
method
There are cases where the callback function or promise might not be resolved, and for such scenarios, we will make use of the catch()
method to handle them. Using the same example as in the previous section, we will add a catch()
method to handle situations where the function is not resolved. Here, we will misspell the JSON file to create an error situation.
fetch("uset.json")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.log(error));
Output
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
The catch()
helps handle situations such as where errors are thrown, and the catch()
covers each and every then()
in the chain or sequence.
Using then()
and catch()
in chaining promises
Now, we have an understanding of how the then()
and catch()
method work. We can show in detail how they work with chaining promisses. For an example on chaining promises, we can fetch JSON data from a dummy user API, and to mimic the fetch
operation in typical JavaScript environment in Node, we can make use of the node-fetch
library. With that, we can chain promises using the then()
method as below.
const fetch = require("node-fetch");
fetch("<https://jsonplaceholder.typicode.com/users/7>")
.then((response) => response.json())
.then((data) => {
console.log(data);
return data;
})
.then((data) => {
const fs = require("fs");
fs.writeFileSync("user.json", JSON.stringify(data));
console.log("User saved to user7.json");
})
.catch((error) => console.error(error));
Output
{
id: 7,
name: 'Kurtis Weissnat',
username: 'Elwyn.Skiles',
email: 'Telly.Hoeger@billy.biz',
address: {
street: 'Rex Trail',
suite: 'Suite 280',
city: 'Howemouth',
zipcode: '58804-1099',
geo: { lat: '24.8918', lng: '21.8984' }
},
phone: '210.067.6132',
website: 'elvis.io',
company: {
name: 'Johns Group',
catchPhrase: 'Configurable multimedia task-force',
bs: 'generate enterprise e-tailers'
}
}
User saved to user7.json
In this example, we are fetching data from a remote server, parsing the response to json and then saving the data to the local storage.
Using async/await
to chain promises
Using the same example as in the previous section, we will rewrite the then()
and catch()
code using the async/await
approach. Here, we await the fetch process and json()
method and make use of their response when there are done. To handle the error or possible rejection, we make use of the try/catch
statement.
const fetch = require("node-fetch");
const fs = require("fs");
async function saveUser() {
try {
const response = await fetch(
"<https://jsonplaceholder.typicode.com/users/7>"
);
const data = await response.json();
console.log(data);
fs.writeFileSync("user.json", JSON.stringify(data));
console.log("User saved to user7.json");
} catch (error) {
console.error(error);
}
}
saveUser();
Output
{
id: 7,
name: 'Kurtis Weissnat',
username: 'Elwyn.Skiles',
email: 'Telly.Hoeger@billy.biz',
address: {
street: 'Rex Trail',
suite: 'Suite 280',
city: 'Howemouth',
zipcode: '58804-1099',
geo: { lat: '24.8918', lng: '21.8984' }
},
phone: '210.067.6132',
website: 'elvis.io',
company: {
name: 'Johns Group',
catchPhrase: 'Configurable multimedia task-force',
bs: 'generate enterprise e-tailers'
}
}
User saved to user7.json
In this example, the fetch()
method returns a promise, which is awaited using the await
keyword. The response.json()
method also returns a promise, which is also awaited. If either of these promises reject, the catch block will be executed.
Using Promise.all()
for chaining promises
Another example of chaining promises is when we want to perform multiple async operations in parallel and wait for them to complete. In this case, the chaining is in parallel rather than in series as in the previous section. We can make use of Promise.all()
method to chain promises. These methods can be used to handle multiple promises at the same time.
Promise.all([promise1, promise2, promise3])
.then((results) => {
// Do something with the results
})
.catch((error) => {
// Handle any error that occurred
});
In this example, the Promise.all()
method is used to wait for multiple promises to resolve and returns an array of the results.
let promise1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(1);
}, 1000);
});
let promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(2);
}, 2000);
});
let promise3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(3);
}, 3000);
});
Promise.all([promise1, promise2, promise3])
.then(function (values) {
console.log(values);
})
.catch(function (error) {
console.error(error);
});
Output
[ 1, 2, 3 ]
Summary
Chaining promises is a powerful technique that allows developers to perform a series of asynchronous operations on a single piece of data in a readable and maintainable way. Chaining promises can be done using the then()
and catch()
methods. Additionally, the Promise.all()
method can be used to handle multiple promises. With the use of these methods, developers can chain multiple promises together to perform a variety of async operations.
References
Promise - JavaScript | MDN (mozilla.org)