Understanding the behavior of catch in Immediately Settled Promises

Understanding the behavior of catch in Immediately Settled Promises

Ever wondered about the order of execution for immediately resolved or rejected promises, does the order even matter ? Let's find out.

Let's take an example first and see the execution here:

const inputs = [Promise.reject(1), Promise.resolve(2)]

Promise.race(inputs)
.then((val)=>console.log("val",val))
.catch((err)=>console.log("err:",err)) //output: err: 1        

as you can see in the above example err: 1 gets logged as output

Let's write our custom Implementation of Promise.race so that we get an understanding of how the input array in the above example is getting processed internally:

  • Promise.race takes an array of promises as input and returns a single Promise
  • As soon as the first item in the array gets resolved or rejected the promise is returned with its input promise state
  • This returned promise settles with the eventual state of the first promise that settles.
  • The returned promise remains pending forever if the array passed is empty

function customPromiseRace(iterable) {
  return new Promise((resolve, reject) => {
    if (iterable.length === 0) {
      return;
    }
    iterable.forEach((item) => {
      Promise.resolve(item)
        .then((value) => {
          resolve(value);
        })
        .catch((err) => reject(err));
    });
  });
}

const inputs = [Promise.reject(1), Promise.resolve(2)];
customPromiseRace(inputs)
  .then((val) => console.log("val:", val))
  .catch((err) => console.log("err:", err)); //output: ?        

what do you think? what should be the output here? As you have seen in the first example you must be thinking that output should be the same that is err: 1.

But surprise... surprise.... output here is val: 2 . By now you must be thinking about what exactly has happened here but my friend that's where the javascript gets interesting.

When I first faced this I kept wondering why this was happening, I tried digging into it and learned something new and interesting while looking for answers to my dilema.

Here comes the reason behind such behavior:

In cases like the above example when the input array contains both immediately resolved and rejected promises (e.g. `[Promise.reject(1), Promise.resolve(2)]`).

`.catch()` is scheduled, and does not run immediately after `.then()`. For immediately settled promises, `then()` run before any `.catch()`, hence the overall Promise is fulfilled with 2 instead of rejected with 1.


So, now the question is how to handle this edge case of immediately settled promises. We are going to make a little adjustment to our customPromiseRace function:


Note: The rejected promises also called `.then()` and the second parameter of `.then()` is the callback to handle rejected promises.

Here we are leveraging `.then()` it takes up to two arguments: callback functions for the fulfilled and rejected cases of the Promise


function customPromise(iterable) {
    return new Promise((resolve, reject) => {
      if (iterable.length === 0) {
        return;
      }
      iterable.forEach((item) => {
          Promise.resolve(item)
          .then((val)=>resolve(val), (err)=>reject(err))
      });
    });
  }
const inputs = [Promise.reject(1), Promise.resolve(2)];
customPromiseRace(inputs)
  .then((val) => console.log("val:", val)) 
  .catch((err) => console.log("err:", err)); //output: err: 1         




Anshuman .

Building Kosmc ??

11 个月

If we change the above approach using async await then it will work fine.

Anshuman .

Building Kosmc ??

11 个月

But surprise... surprise.... output here is val: 1 . -> Change the answer to val:2 ??

要查看或添加评论,请登录

Ashutosh Rai的更多文章

社区洞察

其他会员也浏览了