处理Promise.all中的错误

Jon*_*Jon 210 javascript promise es6-promise

我有一个Promise数组,我正在使用Promise.all(arrayOfPromises)解析;

我接着继续承诺链.看起来像这样

existingPromiseChain = existingPromiseChain.then(function() {
  var arrayOfPromises = state.routes.map(function(route){
    return route.handler.promiseHandler();
  });
  return Promise.all(arrayOfPromises)
});

existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
  // do stuff with my array of resolved promises, eventually ending with a res.send();
});
Run Code Online (Sandbox Code Playgroud)

我想添加一个catch语句来处理单个promise,以防它出错.但是当我尝试时,Promise.all返回它找到的第一个错误(忽略其余的),然后我无法从其余的数据中获取数据数组中的promise(没有错误).

我尝试过像......

existingPromiseChain = existingPromiseChain.then(function() {
      var arrayOfPromises = state.routes.map(function(route){
        return route.handler.promiseHandler()
          .then(function(data) {
             return data;
          })
          .catch(function(err) {
             return err
          });
      });
      return Promise.all(arrayOfPromises)
    });

existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
      // do stuff with my array of resolved promises, eventually ending with a res.send();
});
Run Code Online (Sandbox Code Playgroud)

但这并没有解决.

谢谢!

-

编辑:

下面的答案完全正确,代码因其他原因而破裂.如果有人有兴趣,这就是我最终得到的解决方案......

Node Express服务器链

serverSidePromiseChain
    .then(function(AppRouter) {
        var arrayOfPromises = state.routes.map(function(route) {
            return route.async();
        });
        Promise.all(arrayOfPromises)
            .catch(function(err) {
                // log that I have an error, return the entire array;
                console.log('A promise failed to resolve', err);
                return arrayOfPromises;
            })
            .then(function(arrayOfPromises) {
                // full array of resolved promises;
            })
    };
Run Code Online (Sandbox Code Playgroud)

API调用(route.async调用)

return async()
    .then(function(result) {
        // dispatch a success
        return result;
    })
    .catch(function(err) {
        // dispatch a failure and throw error
        throw err;
    });
Run Code Online (Sandbox Code Playgroud)

在.then之前放置.catch for Promise.all似乎是为了捕获原始promise中的任何错误,然后将整个数组返回到下一个.然后

谢谢!

jib*_*jib 155

Promise.all是全有或全无.它会在阵列中的所有承诺解析后解析,或者在其中一个承诺拒绝后立即拒绝.换句话说,它可以使用所有已解析值的数组进行解析,也可以使用单个错误进行拒绝.

有些库有一些叫做的东西Promise.when,据我所知,它会等待阵列中的所有承诺解析或拒绝,但我不熟悉它,而且它不在ES6中.

你的代码

我同意其他人的意见,你的修复应该有效.它应该使用可能包含成功值和错误对象的数组的数组来解析.在成功路径中传递错误对象是不寻常的,但假设您的代码期望它们,我认为没有问题.

我能想到为什么它"无法解决"的唯一原因是它没有显示我们没有向你展示的代码,以及你没有看到任何关于这个的错误消息的原因是因为这个承诺链没有终止赶上(至于你向我们展示的东西).

我冒昧地将你的例子中的"现有链"分解出来并用一个捕获来终止链.这可能不适合你,但对于阅读本文的人来说,重要的是始终返回或终止链,或者潜在的错误,甚至是编码错误,都会被隐藏(这是我怀疑在这里发生的事情):

Promise.all(state.routes.map(function(route) {
  return route.handler.promiseHandler().catch(function(err) {
    return err;
  });
}))
.then(function(arrayOfValuesOrErrors) {
  // handling of my array containing values and/or errors. 
})
.catch(function(err) {
  console.log(err.message); // some coding error in handling happened
});
Run Code Online (Sandbox Code Playgroud)

  • 现在有一个标准方法“Promise.allSettled()”并提供了良好的支持。请参阅[参考](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled)。 (9认同)
  • 你(和上面的评论)是对的.我的route.handler.promiseHandler需要.catch()并返回错误.我还需要将最终的.catch()添加到链的末尾.感谢您转发在链的每一步都拥有成功/错误处理程序的重要性:). (3认同)
  • 我还发现,如果我在 route.handler.promiseHandler 的 .catch() 中抛出错误,它将自动进入最终捕获。如果我返回错误,它将执行我想要的操作并处理整个数组。 (2认同)
  • 是的,当第一个线程失败时,`Promise.all` 就会失败。但不幸的是,所有其他线程仍然继续运行,直到完成。没有任何东西被取消,更糟糕的是:没有办法取消“Promise”中的线程。因此,无论线程正在做什么(和操作),它们都会继续,它们会更改状态和变量,它们会使用 CPU,但最终它们不会返回结果。您需要注意这一点,以免产生混乱,例如,当您重复/重试呼叫时。 (2认同)

Sol*_*inh 105

新的答案

const results = await Promise.all(promises.map(p => p.catch(e => e)));
const validResults = results.filter(result => !(result instanceof Error));
Run Code Online (Sandbox Code Playgroud)

老答复

我们必须编写自定义Promise.all().这是我在项目中使用的解决方案.错误将作为正常结果返回.在所有承诺完成后,我们可以过滤掉错误.

const results = await Promise.all(promises.map(p => p.catch(e => e)));
const validResults = results.filter(result => !(result instanceof Error));
Run Code Online (Sandbox Code Playgroud)

  • 虽然`e`不一定是'错误'.它可能是一个字符串,例如,如果有人像`Promise.reject('Service not available')那样返回它. (7认同)
  • 为什么要过滤结果?如果您对结果做任何事情,这毫无意义——您需要知道哪个返回值来自哪个承诺的顺序! (4认同)
  • @ shubham-jain与`.then()`和`.catch()`。Promise.resolve()会将值传递给前者,而Promise.reject()**会将值传递给前者。您可以将它们包装在对象中,例如:`p.then(v =>({success:true,value:v}))。catch(e =>({success:false,error:e})))。 (2认同)

Mos*_*ada 57

ES2020Promise类型引入了新方法:Promise.allSettled().

Promise.allSettled当所有输入承诺都得到解决时,会给你一个信号,这意味着它们要么被履行,要么被拒绝。这在您不关心 Promise 的状态,只想知道工作何时完成的情况下很有用,无论它是否成功。

(async function() {
  const promises = [
    fetch('//api.stackexchange.com/2.2'), // succeeds
    fetch('/this-will-fail') // fails
  ];

  const result = await Promise.allSettled(promises);
  console.log(result.map(promise => promise.status));
  // ['fulfilled', 'rejected']
})();
Run Code Online (Sandbox Code Playgroud)

v8 博客文章中阅读更多内容。


Ben*_*uer 19

为了继续Promise.all循环(即使Promise拒绝),我写了一个被调用的实用函数executeAllPromises.此实用程序函数返回带有results和的对象errors.

我们的想法是,你传递给的所有executeAllPromisesPromise都将被包装成一个永远解决的新Promise.新的Promise解决了一个有2个点的阵列.第一个点保存解析值(如果有的话),第二个点保留错误(如果包装的Promise拒绝).

作为最后一步,executeAllPromises累积包装的promises的所有值,并返回带有数组的最终对象results和数组errors.

这是代码:

function executeAllPromises(promises) {
  // Wrap all Promises in a Promise that will always "resolve"
  var resolvingPromises = promises.map(function(promise) {
    return new Promise(function(resolve) {
      var payload = new Array(2);
      promise.then(function(result) {
          payload[0] = result;
        })
        .catch(function(error) {
          payload[1] = error;
        })
        .then(function() {
          /* 
           * The wrapped Promise returns an array:
           * The first position in the array holds the result (if any)
           * The second position in the array holds the error (if any)
           */
          resolve(payload);
        });
    });
  });

  var errors = [];
  var results = [];

  // Execute all wrapped Promises
  return Promise.all(resolvingPromises)
    .then(function(items) {
      items.forEach(function(payload) {
        if (payload[1]) {
          errors.push(payload[1]);
        } else {
          results.push(payload[0]);
        }
      });

      return {
        errors: errors,
        results: results
      };
    });
}

var myPromises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.reject(new Error('3')),
  Promise.resolve(4),
  Promise.reject(new Error('5'))
];

executeAllPromises(myPromises).then(function(items) {
  // Result
  var errors = items.errors.map(function(error) {
    return error.message
  }).join(',');
  var results = items.results.join(',');
  
  console.log(`Executed all ${myPromises.length} Promises:`);
  console.log(`— ${items.results.length} Promises were successful: ${results}`);
  console.log(`— ${items.errors.length} Promises failed: ${errors}`);
});
Run Code Online (Sandbox Code Playgroud)

  • 这可以更简单地完成。见 http://stackoverflow.com/a/36115549/918910 (2认同)

Kam*_*ski 12

Promise.allSettled

而不是 Promise.all 使用Promise.allSettled等待所有承诺解决,无论结果如何

let p1 = new Promise(resolve => resolve("result1"));
let p2 = new Promise( (resolve,reject) => reject('some troubles') );
let p3 = new Promise(resolve => resolve("result3"));

// It returns info about each promise status and value
Promise.allSettled([p1,p2,p3]).then(result=> console.log(result));
Run Code Online (Sandbox Code Playgroud)

填充物

if (!Promise.allSettled) {
  const rejectHandler = reason => ({ status: 'rejected', reason });
  const resolveHandler = value => ({ status: 'fulfilled', value });

  Promise.allSettled = function (promises) {
    const convertedPromises = promises
      .map(p => Promise.resolve(p).then(resolveHandler, rejectHandler));
    return Promise.all(convertedPromises);
  };
}
Run Code Online (Sandbox Code Playgroud)


小智 10

正如@jib所说,

Promise.all 是全有还是全无。

但是,您可以控制“允许”失败的某些承诺,我们希望继续进行.then

例如。

  Promise.all([
    doMustAsyncTask1,
    doMustAsyncTask2,
    doOptionalAsyncTask
    .catch(err => {
      if( /* err non-critical */) {
        return
      }
      // if critical then fail
      throw err
    })
  ])
  .then(([ mustRes1, mustRes2, optionalRes ]) => {
    // proceed to work with results
  })
Run Code Online (Sandbox Code Playgroud)


Nay*_*tel 7

Using Async await -

这里,一个异步函数func1返回一个解析值,而func2在这种情况下抛出错误并返回null,我们可以按需要处理它并相应地返回。

const callingFunction  = async () => {
    const manyPromises = await Promise.all([func1(), func2()]);
    console.log(manyPromises);
}


const func1 = async () => {
    return 'func1'
}

const func2 = async () => {
    try {
        let x;
        if (!x) throw "x value not present"
    } catch(err) {
       return null
    }
}

callingFunction();
Run Code Online (Sandbox Code Playgroud)

输出为-['func1',null]


Moh*_*oud 6

如果你使用q库https://github.com/kriskowal/q 它有q.allSettled()方法可以解决这个问题你可以处理每个承诺,取决于它的状态要么fullfiled还是拒绝所以

existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
  return route.handler.promiseHandler();
});
return q.allSettled(arrayOfPromises)
});

existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
//so here you have all your promises the fulfilled and the rejected ones
// you can check the state of each promise
arrayResolved.forEach(function(item){
   if(item.state === 'fulfilled'){ // 'rejected' for rejected promises
     //do somthing
   } else {
     // do something else
   }
})
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Run Code Online (Sandbox Code Playgroud)


Asa*_*af 5

Promise.all用过滤器解决

const promises = [
  fetch('/api-call-1'),
  fetch('/api-call-2'),
  fetch('/api-call-3'),
];
// Imagine some of these requests fail, and some succeed.

const resultFilter = (result, error) => result.filter(i => i.status === (!error ? 'fulfilled' : 'rejected')).map(i => (!error ? i.value : i.reason));

const result = await Promise.allSettled(promises);

const fulfilled = resultFilter(result); // all fulfilled results
const rejected = resultFilter(result, true); // all rejected results
Run Code Online (Sandbox Code Playgroud)