Javascript Promises in Depth | Complete Guide

vugz15i3sz2asv64clw3

In this blog, I will cover Javascript Promises in Depth. I will discuss all functions related to Promise and Features of Promise.

Javascript Promises in Depth

What is promise?

Promise, in the javascript program, means it promises that I will give you a result after a period of time (usually an asynchronous operation). It is a solution to asynchronous programming. Syntactically speaking, a native Promise is an object, from which asynchronous operation messages can be obtained.

Features of promise

  • The state of the object is not affected by the outside world.

A promise has three states pending(in progress), fulfilled(successful) and rejected(failed). Only the result of an asynchronous operation can determine which state it is currently in, and no other operation can change this state.

  • Once you change from the waiting state to another state, you can never change the state.

There are only two status changes for promise:
pending(in progress) –> fulfilled(successful);
pending(in progress) –> rejected(failed).
When the status change is over, it is called resolve(fixed). Once the status becomes resolved, it cannot be changed again.

  • Once a new Promise is created, it will be executed immediately and cannot be cancelled halfway.
  • If the callback function is not set, errors thrown inside the Promise will not be reflected to the outside.
  • When it is in the pending state, it is impossible to know which stage it is currently in (just started or is about to be completed).

Promise instance operation

Javascript Promises in Depth

First create a Promise instance

let promise = new  Promise ( function ( resolve,reject ){
     if ( /*Asynchronous execution succeeded*/ ){
         resolve (value);
    } else {
         reject (error);
    }
})
promise.then(function (){
     //Operation after the callback is successfully executed 
}, function (){
     //The operation after the callback fails, optional
});

The Promise constructor accepts a function as a parameter, and the two parameters of the function are resolve and reject. They are two functions, provided by the JavaScript engine. When the asynchronous operation succeeds ( pending--fulfilled), the resolve(value)function is called to pass the operation result as a parameter, and when the asynchronous operation fails ( pending--rejected), the reject(error) function is called to return the error. After the Promise instance is generated, use then methods to specify the callback functions for the resolved state and rejected state respectively.

Let’s take a look at the method of constructing function prototype

Promise.prototype.then()
  • The function is to add a callback function when the state of the Promise instance changes . Accepts two callback functions as parameters. The first callback function is called when the state of the Promise object becomes resolved, and the second callback function is called when the state of the Promise object becomes rejected. Among them, the second function is optional and does not have to be provided.
  • The method returns another Promise object, and then you can call then method later.
Promise.prototype.catch()
  • It is an alias of .then(null, rejection)or .then(undefined, rejection), which is used to specify the callback function when an error occurs. The error of the Promise object has a “bubble” nature and will be passed backwards until it is caught. In other words, the error will always be caught by the next catch statement .
  • The method returns a Promise object, so you can call then method later.

The above code can also be understood like this:

getUserDataJSON( '/user.json' ).then(function(user_data) {
       // ... 
}).catch ( function ( error ) {
   // handle errors that occur when getJSON and the previous callback function are running 
  console.log('An error occurred!',error);
});
Promise.prototype.finally()
  • The method is used to specify the callback function that will be executed regardless of the final state of the Promise object. This method is introduced into the standard by ES2018.
  • The method’s callback function does not accept any parameters, which means that there is no way to know whether the previous Promise state is fulfilled or rejected. This shows that finally the operation in the method should be independent of the state and not dependent on the execution result of the Promise.
promise.then(()=>{}).catch(()=>{}).finally(()=>{
       // operation
});
// is equivalent to 
promise.then(result=>{
         // operation 
    return result;
}).catch (error=>{
         // operation 
    throw error;
});
Promise chain call
  • If the Promise instance is resolve then it will pass its value to the next success callback so you can chain calls the instance.
  • If there is an exception in the then, the next failure callback of the then will be followed, and the catch will catch the exception that was not caught.
Promise.resolve(1).then(res=>{
         throw new Error("Error!");
         return  2  //Packed into Promise.resolve(2)
}).then().then().catch(err=>3).then(res=>console.log(res)) //OUTPUT: Error!
  • If return is used in then, then the value of return will be Promise.resolve()wrapped, and no parameters can be passed in then. If it is not passed, it will be passed to the next then.
Promise.resolve(1).then(res=>{
         console.log(res) //OUTPUT: 1
         return 2;  //Packed into Promise.resolve(2) 
}).catch(err=>3).then().then(res=>console.log(res)) //OUTPUT: 3

Promise API

Promise.resolve()

Convert (wrap) existing objects into promise objects. Four parameter types:

  • Pass without parameters.It return a new promise object with a state of resolve.
let p = Promise.resolve()    // p is promise
  • The parameter is a Promise instance. It return the current promise instance
  • The parameter of resolve is an object with the then method
let data = {
     then : function(resolve,reject){
         resolve ( 'object with then method' )
    }
}
Promise.resolve(data).then((res)=>console.log(res)) // 'object with then method' is returned
  • The parameter is none-empty, none-then method object. It return a new promise object with a resolve state, so the then callback function will be executed immediately. The parameters of the method Promise.resolve will be passed to the callback function at the same time.
let p = Promise.resolve('foo')
 // equivalent to 
let p = new Promise(resolve=>resolve('foo'))
p.then(res=>console.log(res)) //'foo'

Promise.reject()

  • When the parameter is a non-then object, the Promise.reject(reason) method will also return a new Promise instance whose status is rejected
let p =   Promise.reject('error')
 // equivalent to 
let p = new Promise ((resolve,reject)=>reject('error'))
 // callback for handling errors 
p.then(null,res=>console.log(res)) // 'error'
  • The parameter of resolve is the object with the then method.What is returned is not then the callback function of the method, but the data object itself
let data = {
     then : function(resolve,reject){
         reject('The object with the then method has an error')
    }
}
Promise.resolve(data).then(null,res=>console.log(res)) // data 
// equivalent 
Promise.resolve(data).catch(res=>console.log(res)) / /data

Promise.all()

This method wraps multiple promise instances into a new promise instance.

let p = Promise.all([p1,p2,p3])

The parameter does not have to be an array, but it must be an iterable Iterator, and each returned member (p1, p2, p3) is a Promise instance. If not, the Promise.resolve() method will be called first to convert the parameter to a Promise instance, and then go further deal with.

var p1 = Promise.all(["InfoHubBlog","Best","Website"]);
var p2 = Promise.all(["InfoHubBlog","Best","Website",Promise.resolve(444)]);
var p3 = Promise.all(["InfoHubBlog","Best","Website",Promise.reject(555)]);
setTimeout(function(){
     console.log(p1); // Promise {<state>: "fulfilled", <value>: Array[3]} 
     console.log(p2); // Promise {<state>: "fulfilled", < value>: Array[4]} 
     console.log(p3); // Promise {<state>: "rejected", <reason>: 555}
});
p1.then(function(posts) {
   // ...will call back when there is a return value 
}). catch ( function ( reason ){
   // ... 
});
  • If all Promise are fulfilled then state become fullfilled and the value is passed to then callback function.
  • If any one element in iterator is rejected then the state become rejected and the rejected value is passed to catch callback function.
  • Promise.all() is an asynchronous resolution . Only when the state of all instances has changed fulfilled, or one of them has changed rejected, will the callback function then and catch method behind the Promise.all method be called . But if and only if the passed iterable is empty , Promise.all will resolve synchronously 
let p1= Promise.all(["Bye"]).then(a=>console.log(a));
let p2= Promise.all([]).then(el=>console.log("Hi"));
/*
OUTPUT:
Hi
["Bye"]
*/
  • Handling errors . Normally, when one of the instances returns rejectedPromise.all the catch method will be called and the first error will be returned. But in actual application, we want all instances to return parameters to form an array regardless of success or failure, then we can call the instance’s own catch method to avoid this situation.
const p1=new Promise((resolve,reject)=>{
   resolve('hello'); //resolved 
}).then(result=>result).catch(e=>e);

const p2=new Promise((resolve,reject)=>{
   throw new Error('reported'); //rejected 
}).then(result=>result).catch(e=>e);

Promise.all([p1, p2])
.then(result=>console.log(result)) // ["hello", Error: Error reported] 
.catch(e=>console.log(e));

P1 will resolved, p2 will be the first rejected, but p2 has its own catch method, which returns a new Promise instance, and p2 actually points to this instance. The instance will become resolved after the catch method is executed, causing both instances in the Promise.all() method parameter to be resolved , so the callback function specified by the then method will be called instead of the callback function specified by the catch method.

  • The principle of js native implementation of Promise.all
//Add an all method to the Promise class to accept an array of  promises passed in Promise.all 
Promise.all = function(promiseArrs) { 
    return new Promise((resolve,reject) => { //Return a new Promise 
     let arr = []; //Define an empty array to store the result 
     let i = 0 ;
     function handleData(index,data) { //Data processing function
        arr[index] = data;
        i++;
        if (i === promiseArrs.length) { //When i is equal to the length of the passed array 
            resolve (arr); //Execute resolve and put the result in
        }
     }
     for(let i = 0;i<promiseArrs.length;i++) { //loop through the array 
        promiseArrs[i].then((data)=>{
             handleData (i,data); //pass the result and index into handleData function
        }, reject)
     }
    })
}
  • If the experience of all is not good, then we can also make some method by ourselves, which means that all failures are considered failures.
Promise.some = function(promiseArrs) {
   return new Promise((resolve,reject)=>{
    let arr = []; //Define an empty array to store the result 
    let i = 0;
    function handleErr(index,err) { // Error handling function
      arr[index] = err;
      i++;
      if (i === promiseArrs. length ) { //When i is equal to the length of the passed array, 
        reject (err); //Execute reject and put the result in
      }
    }
    for(let i=0;i<promiseArrs.length;i++) { // loop through the array 
       promiseArrs[i].then(resolve,(e)=>handleErr(i, e))
   }
  })
}

Promise.allSettled – Compatibility is not friendly

This method is similar to promise.all, it is to solve the unreasonable appearance of the all method in handling errors. Its parameter accepts an array of Promises and returns a new Promise. The only difference from all is that it will not be short-circuited, which means that when the Promises are all processed, we can get the status of each Promise, regardless of whether the processing was successful.

  • Similar to all, when its own instance has a catch callback, the status of each instance becomes fulfilled
const p3 = new Promise((resolve, reject) => {
  resolve('hello'); //resolved
}).then(result => result).catch(e => e);

const p4 = new Promise((resolve, reject) => {
  throw new Error('Reported an error');//rejected
}).then(result => result).catch(e => e);

Promise.allSettled([p3, p4])
.then(result => console.log(result))
.catch(e => console.log(e));
Screenshot 2021 09 18 at 1.08.54 PM
  • No catch receiving error, return its own status and callback parameters
const p5 = new Promise((resolve, reject) => {
  resolve('hello'); //resolved
}).then(result => result)

const p6 = new Promise((resolve, reject) => {
  throw new Error('Reported an error');//rejected
}).then(result => result)

Promise.allSettled([p5, p6])
.then(result => console.log(result))
.catch(e => console.log(e));
Screenshot 2021 09 18 at 1.09.33 PM

Promise.race()

This method also packs multiple Promise instances into a new Promise instance. The other features are similar to all. The difference with all is: the race method is like a race. If several instances run together, whoever arrives first will succeed. Whoever resolves, or who ran to the midway and fell into an abnormal situation and failed, reject whoever, regardless of success or failure, first capture the first completed.

  • Capture the first successful instance callback function
let p1 = Promise.resolve('1')
let p2 = Promise.resolve('2')
Promise.race([p1,p2]).then(res=>conseloe.log(res)) //OUTPUT: '1'
  • Capture the first result
let p1 = Promise.resolve("1");
let p2 = Promise.reject("ERR2");
Promise.race([p1,p2]).then(res=>console.log(res)) //OUTPUT: Promise {<resolved>: "1"}
  • Catch the first error
let p1 = Promise.reject("ERR1");
let p2 = Promise.reject("ERR2");
Promise.race([p1,p2]).catch(console.log) //OUTPUT: Promise {<reject>: "ERR1"}
  • The design principle of native implementation of Promise.race()
Promise._race = iterator  =>{
    return new Promise((resolve,reject)=>{
        iterator.forEach(item=>{
            Promise.resolve(item).then(resolve).catch(reject)
        })
    })
}

Promise.try

In the actual development and use of promises, it is hoped that the internal code of the function wrapped by the promise will allow the synchronous function to be executed synchronously, and the asynchronous function will be executed asynchronously

let fn = () =>console.log('Sync 1');
Promise.resolve().then(fn)
console.log('Sync 2')
//OUTPUT: 
//'Sync 2'
//'Sync 1'
  • Application of Promise.try
    This method is used to simulate 
Try catch in JavaScript is exception handling mechanism. The code that may be wrong is placed in the try statement block. If there is an error, it will be caught by catch to handle the exception. If you don't catch an error, it will cause the program to crash. finally : Regardless of the result, it is allowed to execute code after try and catch .
try {
         // code block for testing
}
catch(err){
          //Code block for handling errors
} 
finally {
          //code block to be executed regardless of the result of try/catch 
}
  • application
let fn = () => console.log('Sync 1');
Promise.try(fn);
console.log('Sync 2');
//'Sync 1' 
//'Sync 2'
Solve the current method of letting synchronous functions execute synchronously and asynchronous functions asynchronously execute
  • Method 1: Using the async anonymous function, the async function inside will be executed immediately, so if fn is synchronous, you will get a synchronous result; if fn is asynchronous, you can use then to specify the next step, if you want to catch errors, use catch method.
let fn=()=>console.log('Sync 1');
(async ()=>fn())()
.then(resolve)
.catch(err=>console.log(err))
console.log('Sync 2')
//After log 
//'Sync 1' 
//'Sync 2'
  • Method two: use the anonymous function that promises to execute immediately
let fn=()=>console.log('sync 1');
(()=>new  Promise(
        resolve => resolve(fn())
))()
console.log('sync 2')
// log after 
// 'sync 1' 
// 'sync 2'

Hope you like our “Javascript Promises in Depth” blog. Please subscribe to our blog for upcoming blogs.

Happy Coding!

9 Comments on "Javascript Promises in Depth | Complete Guide"

  1. ersätta vetemjöl med majsmjöl | September 27, 2021 at 6:41 am | Reply

    What’s up friends, good article and pleasant arguments commented at this place, I am really enjoying by these.

  2. Krishna Purohit | September 28, 2021 at 2:16 pm | Reply

    Very nice article. Clears all concepts about promises.

  3. coca cola gravid | October 24, 2021 at 6:16 pm | Reply

    A motivating discussion is definitely worth comment. I do believe that you should write more on this topic, it might not be a taboo matter but generally people do not talk about such subjects. To the next! Many thanks!! coca cola gravid

  4. Discover the best ever for free!

  5. israelnightclub.com | April 2, 2022 at 4:09 pm | Reply

    Im very happy to find this web site. I want to to thank you for ones time just for this fantastic read!! I definitely appreciated every part of it and i also have you saved as a favorite to see new information in your blog.

  6. נערות ליווי | April 16, 2022 at 3:34 pm | Reply

    I must thank you for the efforts youve put in penning this site. I am hoping to check out the same high-grade blog posts by you in the future as well. In fact, your creative writing abilities has motivated me to get my very own blog now 😉

Leave a comment

Your email address will not be published.


*