Search code examples
javascriptnode.jsecmascript-6es6-promise

Promise.all wrapper which can trap errors


I have this verbatim in a simple script:

Promise.all(links.map(function (l) {
  return Promise.resolve(require(l).r2gSmokeTest())
     .then((v:any) => ({path: l, result: v}));
}))
.then(function(results){

})
.catch(function(e){

}):

the problem is that if the require() call throws an error for whatever reason, the promise chain won't catch it.

is the simplest thing to do to avoid this to wrap Promise.all in a function, like so:

const getAllPromises = function(links){
   return Promise.resolve(null).then(function(){
       return Promise.all(links.map(function (l) {
         return Promise.resolve(require(l).r2gSmokeTest())
         .then((v:any) => ({path: l, result: v}));
}));

it seems to me that maybe Promise.all should have a different API, something like:

Promise.all(function(){
   return values.map(v => whatever);
});

that way any errors can be trapped, if Promise.all is not called within a Promise chain...


Solution

  • Use an async function which can't throw - it will only return a rejected promise when an exception happens:

    Promise.all(links.map(async function (l) {
      const v: any = await require(l).r2gSmokeTest();
      return {path: l, result: v};
    }))
    

    In general, the expectation for any function that does something asynchronous is to always return a promise and never throw synchronously. Your map callback should adhere to that - and try … catch (e) { return Promise.reject(e); } around the require call if necessary. You might also consider using a helper function that works like Bluebird's Promise.try.