Javascript Promises are another way of handling asynchronous programming in JavaScript. Promise in Javascript represents a piece of task that is wrapped in asynchronous operation and notified whenever the asynchronous operation is completed or failed at some point in the future. Whenever a promise is run there are two possible outcomes from a promise, either promise is completed or failed.
Javascript promise can have one of three states as follow.
- Pending: initial state, neither fulfilled nor rejected.
- Fulfilled: The promised operation was successfully completed.
- Rejected: Promise failed to complete because an error occurs during promise execution.
Promises were introduced in ES2015 to solve the callback hell problem, but they have introduced complexity on their own, especially when we have nested or chained the promises, then it is difficult to read and understand.
Using (Async and await), with promise, makes asynchronous operations look like synchronous operations, thus making Javascript promises easy to read and understand. We have a complete tutorial on how to use promise with (async and await).
Creating Javascript promise
In Javascript, we can easily create promises by instantiating a new keyword on the Promise class. The new Promise object receives a single function as a parameter (known as the executor function), which inturns take two arguments. The first argument resolve() function is called whenever a promise is successfully completed, and the second argument reject() function is called when a promise fails its operation.
The syntax of new promise
Promise(executorCallback(resolve, reject));
const promiseObject = new Promise((resolve, reject) => {
// Do something asynchronously
if (success) {
resolve(value);
} else {
reject(error);
}
});
We can’t guarantee that asynchronous operation will succeed or not. Let’s say an example of a Promise, asynchronous trying to retrieve data from the server. This promise is either successful or failed. If it failed because of server issues, because of some network error, or other reasons.
How to handle Javascript promise?
The promise is not invoked until we didn’t call it using .then
on promise object. When calling .then on a promise object, we are setting up a “callback function” for both success and error. Promise.then() function takes two optional arguments, a callback for success and another for failure.
promiseObject.then(
(result) => console.log(result), //For success
(error) => console.log(error)); //For failure
Javascript Promise member functions
The promise class has three member functions that can be used to handle promise fulfillment and rejection. These functions are called promise handlers, we have then(), catch(), and finally() member function. We can add the following member function on the promise object and we already learned about then() function.
- catch(): Take one function argument for handling promise failure or rejection and it calls only when the promise is rejected.
- finally(): Takes one function argument and both the catch and finally function are optional. Adding finally will attach further operations on promise regardless of promise success or failure.
Javascript promise example
We have learned what is a promise, let us demonstrate a few Javascript promise examples. Here in the promise body, we have added setTimeout, in a real application we added asynchronous operations like API calls. When we successfully complete remote API calls, we can pass return data from the server, here response as an argument in resolve.
We call the firstPromise, on the completion of 250 milliseconds, this promise is resolved with returning string content “Success on promise completion !” in then() promise handler will console.log it. In our case, we send messages as strings as arguments in resolve().
Promise Reference Used by the Calling Function
const promiseRef: Promise = this.aTimetakingTask(false);
promiseRef.then(
(result) => console.log(result),
(error) => console.log(error));
Promise.finally() takes one function as an argument and it is called regardless of Promise resolve or reject condition.
const myPromise = new Promise((resolve, reject) => {
console.log('Starting asynchronous work!');
setTimeout(() => { resolve('Promise completed'); }, 1000);
});
myPromise.then(value => console.log(value))
.catch((err) => console.log('Error' , err))
.finally(value => {
console.log('Finally!');
});
We get the following output from the above code.
Starting asynchronous work!
index.html:18 Promise completed
index.html:21 Finally!
Error handling in Promise
In our previous example, we had demonstrated Javascript promise example on success case, let’s demonstrate how to handle error in Promise. We can handle Promise errors in two ways
- First, then handler callback of the second argument is for handling Promise error.
- Or calling catch handler on promise object.
Let us demonstrate each of these two examples of handling Promise error. Let’s demonstrate the first example of promise error handling in the then() handler’s second argument to handle the error. In the example, the success and error handler are both defined on the then() function.
In the second example, we have demonstrated Promise error handling using the catch function. The handling error using the catch callback function is more readable and cleaner. Alternatively, we may chain success and error handlers using the catch() function.
The catch error handling is useful to chain success and error handlers. It handles the errors not only in resolve or reject, but also in the success handler of then() when we have chains of Promises.
Chaining Promises in Javascript
Every time we call then() on a promise, it returns a new promise. This makes promises chainable and the output of one promise may use as input for another promise.
Here we demonstrate examples of promises chaining in Javascript. We have three promise chaining, we are using a regular function, and in a real application, we have an asynchronous operation. Here is what we are doing.
- First, we call myPromise, to check num is greater than 11, if so then we resolve success by returning the number 11.
- In the second chaining we call findSquare Promise we are finding the square of 11 which is 121 and rejecting the number 121.
- As findSquare promise return reject, then we are calling reject callback that is checkOdd callback.
- In checkOdd promise, we check 121 as odd or even, if odd then is resolved by sending the message Odd.
const myPromise = new Promise((resolve, reject) => {
const num = 11;
if (num > 5) {
resolve(num);
} else {
reject('Number is too small');
}
});
myPromise
.then(findSquare)
.then(checkEven, checkOdd)
.then(result =>
console.log('All promise handle complete and result of last promise call : ' + result))
.catch((err) => {
console.log('Error handler in catch : ', err);
});
function findSquare(num) {
return new Promise((resolve, reject) => {
const square = num * num;
reject(square);
});
}
function checkEven(num) {
return new Promise((resolve, reject) => {
if (num % 2 == 0) {
resolve('Even');
} else {
reject('Odd');
}
});
}
function checkOdd(num) {
return new Promise((resolve, reject) => {
if (num % 2 != 0) {
resolve('Odd');
} else {
reject('Even');
}
});
}
When you invoke then() on a promise, you pass a function as a parameter. Whatever that function returns will be the value for the next then() in the chain.
What is Javascript Promise all?
The promise.all() is Javascript static class function and Promise all is not instantiated on calling new on Promise class.
The (async and await) with promise provide lots of advantages, it provides cleaner and more readability in promise. Used (async and await) with Promise when Promises order is important and output of one promise become input to next promise.
Syntax of Javascript Promise all
Promise.all() takes in an array of promises and when all of the promises have been resolved, the then handler will be called.
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results))
.catch(err => console.log(err));
OR
const [data1, data2, data3] = await Promise.all([promise1, promise2, promise3])
We have three promise when all promise is handled successfully, then the handler function is called and the result of then is an array with value resolved from all the above three promise. Let’s demonstrate an example.
const promise1 = new Promise((resolve, reject) =>
setTimeout(() => resolve('Promise 1'), 1000));
const promise2 = new Promise((resolve, reject) =>
setTimeout(() => resolve('Promise 2'), 2000));
const promise3 = new Promise((resolve, reject) =>
setTimeout(() => resolve('Promise 3'), 300));
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results));
The output of the above three promise results is an array containing resolve values from promises.
Promise.all() will reject immediately upon any of the input promises rejected and then the success handler is not called, instead catch handler is called when there is rejection in the promise.
Javascript Promise race
The Promise race is like Promise all is a static Javascript function and not instantiated by a new object Promise. It can handle multiple promises in an array when one of the promises is successfully completed, then the remaining promises are aborted.
The Promise.race() function is designed to handle only the first promise fulfilled or rejected and calls the promise fulfillment handler for the first promise completed.
Promise rejection handling with Promise.race() works the same way as Promise.all(). Only the first rejected promise is handled. The other promises are ignored, regardless of the fulfillment state.
Conclusion:
The Promise is important for handling asynchronous operations in Javascript. Using Promise with (async and await), will make Promise more readable and make it like an asynchronous operation. But when we have a set of Promises where the order is not important then use Javascript Promise all.
Related:
- Javascript Map and Join function
- Differences between Javascript let vs var
- How to use Javascript detect browser type
- Functional Programming in JavaScript