Home > Mobile >  What happens to rejected promises inside Promise.race?
What happens to rejected promises inside Promise.race?

Time:12-18

Normally, when a Promise in JavaScript rejects without handling, we get unhandled promise rejection error.

But then what happens to all rejected promises ignored by Promise.race logic? Why don't they throw the same error?

Consider the following test:

const normal = new Promise((resolve, reject) => {
    setTimeout(() => resolve(123), 100);
});

const err = new Promise((resolve, reject) => {
    setTimeout(() => reject('ops'), 500);
});

const test = Promise.race([normal, err]);

test.then(data => {
    console.log(data);
});

The test above simply outputs 123, but no unhandled promise rejection error for our err promise.

I'm trying to understand what happens to all those rejected promises then, hence the question.

We potentially end up with a bunch of loose promises that continue running in the background, without any error handling, and never any reporting about unhandled promise rejections. This seems kind of dangerous.


Case in point. I was trying to implement combine logic for asynchronous iterables (similar to this), which requires use of Promise.race, while at the same time tracking rejections of any parameters passed into it, because the combine function needs then to reject on the next request.

CodePudding user response:

Normally, when a Promise in JavaScript rejects without handling, we get unhandled promise rejection error.

Yes, this happens when a promise is getting rejected that had never gotten .then() called on it to install handlers, i.e. one that is the final promise of a chain.

(Notice that .catch(onRejected) internally delegates tot .then(undefined, onRejected), so the promise is getting marked as handled the same.)

But then what happens to all rejected promises ignored by Promise.race logic? Why don't they throw the same error?

The Promise.race does call .then() on all promises in its argument, marking them as handled:

Promise.race = function(thenables) {
    return new Promise((resolve, reject) => {
        for (const thenable of thenables) {
            Promise.resolve(thenable).then(resolve, reject);
        }
    });
};

Notice it doesn't re-throw the error when the outer promise is already resolved, it's just getting ignored. This is by design: when using Promise.race, you state that you are only interested in the first result, and everything else can be discarded. Causing unhandled promise rejections from the promises that didn't win the race to crash your application would be rather disruptive.

CodePudding user response:

From MDN:

The Promise.race() method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.

Your code fulfills because the faster promise calls resolve. Swap them around and it rejects.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
}).catch((value) => {
  console.log('error ', value);
});

  • Related