简体   繁体   中英

Why do I get unhandled promise rejection in this situation?

I have the next function in my code that can interrupt execution due to several reasons:

const getAndCheckItem = async (itemId) => {
    try {
        const item = await getItem(itemId);
        if(item.firstFail) {
            throw "First fail";
        }
        if(item.secondFail) {
            throw "Second fail";
        }
        if(notGood(item)) {
            throw "Third fail"; 
        }

        return item;
    }
    catch(err) {
        return Promise.reject(err);
    }
};

If I call it inside some other async function in the following way, everything is fine and any internal throw is handled:

try {
    item = await getAndCheckItem(ids[0]);
}
catch(err) {
    // handle error
}

However, when I call the function for several ids:

try {
    items = await Promise.all([ids.map(value => getAndCheckItem(value))]);
}
catch(err) {
    // handle error
}

I receive unhandled promise reject in case of any internal throw. I understand that Promise.all() considers any returned non-promise value as a resolved promise. However, Promise.reject(err) should return a Promise and thus be handled. What's the problem?

Promise.all() considers any returned non-promise value as a resolved promise.

Sure, but when you do

return Promise.reject(err);

you're returning a Promise, so once it gets unwrapped by the caller, the getAndCheckItem call results in a rejected Promise. Doing return Promise.reject(err) is very similar to doing throw err inside something async .

If all you do in a catch is re-throw or return a rejected Promise, there's not much point to it - you may as well leave that part off completely, and just let the caller handle it:

const getAndCheckItem = async (itemId) => {
  const item = await getItem(itemId);
  if(item.firstFail) {
    throw "First fail";
  }
  if(item.secondFail) {
    throw "Second fail";
  }
  if(notGood(item)) {
    throw "Third fail"; 
  }
  return item;
}

You're also currently passing an array of arrays of Promises to Promise.all :

await Promise.all([ids.map(value => getAndCheckItem(value))]);

In which case the Promise.all won't really do anything, since the only item of its array is a non-Promise (another array). If any of the inner promises reject, they won't be handled, so you'll get an unhandled rejection.

Instead, pass an array of Promises to Promise.all :

await Promise.all(ids.map(value => getAndCheckItem(value)));

Or, more concisely:

await Promise.all(ids.map(getAndCheckItem));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM