Search code examples
javascriptnode.jspromisetry-catch

Unhandled promise rejection with Promise.allSettled and try/catch


My idea is as follows: I want to send multiple requests simultaneously without having to wait until priors execution.

So my pseudo code looks as follows:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function failingRequest(){
    return new Promise((resolve, reject) => {
        reject('Request failed');
    });
}

function successRequest(){
    return new Promise((resolve, reject) => {
        resolve('Request success');
    });
}

async function main() {
    try {
        let executions = [];
        executions.push(failingRequest());
        await sleep(4000);
        executions.push(successRequest());
        let result = await Promise.allSettled(executions);
        console.log(result);
    } catch (err) {
        console.log('Outer error occured.');
        console.log(err.message);
    }

    console.log('done');
}
main();

Running this code here works as intended in the browser but gives me following output running with node:

node:761) UnhandledPromiseRejectionWarning: Request failed
api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:761) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exi not handled will terminate the Node.js process with a non-zero exit code.
[
  { status: 'rejected', reason: 'Request failed' },
  { status: 'fulfilled', value: 'Request success' }
]
done
(node:761) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)

Any idea why this is happening?

Note that I only inserted sleep so I could test if the catch block will be executed in case the first request fails WHICH WOULD NOT BE THE DESIRED BEHAVIOR. I want to initiate those requests all at the same time and I do not care if one fails. I want to check later with let result = await Promise.allSettled(executions); which requests worked and which failed. I hope this is clear.


Solution

  • Interesting question - the problem is that you're not actually simulating async requests. In fact your two request-methods are simply creating promises which are resolved/rejected synchronously/immediately. You would need to put await before failingRequest() in order for the rejected promise to be caught in the surrounding try/catch but this is probably not what you want.

    Instead you should not "start" the promises immediately, it should rather be something like:

    try {
            let executions = [];
            executions.push(failingRequest);
            await sleep(4000);
            executions.push(successRequest);
            let result = await Promise.allSettled(executions.map(promiseFn => promiseFn()));
            console.log(result);
        } catch (err) {
            console.log('Outer error occured.');
            console.log(err.message);
        }
    

    This will log

    [
      { status: 'rejected', reason: 'Request failed' },
      { status: 'fulfilled', value: 'Request success' }
    ]
    done
    

    as expected.