处理 Promise.all 中的错误

IT技术 javascript es6-promise
2021-01-31 17:04:08

我有一系列要解决的 Promise Promise.all(arrayOfPromises);

我继续继续Promise链。看起来像这样

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();
});

我想添加一个 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();
});

但这并不能解决。

谢谢!

——

编辑:

下面的答案是完全正确的,由于其他原因,代码被破坏了。如果有人感兴趣,这是我最终得到的解决方案......

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;
            })
    };

API 调用(route.async 调用)

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

.catchfor放在 thePromise.all之前.then似乎是为了从原始Promise中捕获任何错误,但随后将整个数组返回到下一个.then

谢谢!

6个回答

Promise.all全有或全无。一旦数组中的所有Promise解决,它就会解决,或者在其中一个拒绝后立即拒绝。换句话说,它要么使用所有已解析值的数组进行解析,要么以单个错误拒绝。

一些库有一个叫做 的东西Promise.when,我理解它会等待数组中的所有Promise解决或拒绝,但我不熟悉它,它不在 ES6 中。

你的代码

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

我能想到为什么它“无法解决”的唯一原因是它在您没有向我们展示的代码中失败,并且您没有看到任何关于此的错误消息的原因是因为此Promise链没有以 final 终止抓住(就您向我们展示的内容而言)。

我冒昧地从您的示例中分解出“现有链”并用捕获终止链。这可能不适合您,但对于阅读本文的人来说,始终返回或终止链很重要,否则潜在的错误,甚至编码错误,将被隐藏(我怀疑这里发生了这种情况):

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
});
现在有一种标准方法Promise.allSettled()得到了不错的支持。参考
2021-03-16 17:04:08
你(和上面的评论)是对的。我的 route.handler.promiseHandler 需要 .catch() 并返回错误。我还需要将最终的 .catch() 添加到链的末尾。感谢您传达在链的每一步都有成功/错误处理程序的重要性:)。
2021-03-19 17:04:08
是的,Promise.all失败,当第一个线程失败时。但不幸的是,所有其他线程仍然继续运行,直到它们完成。没有任何东西被取消,更糟糕的是:没有办法取消Promise. 所以无论线程在做什么(和操作),它们都会继续,它们会改变状态和变量,它们会使用 CPU,但最后它们不会返回它们的结果。您需要注意这一点以免造成混乱,例如当您重复/重试呼叫时。
2021-03-30 17:04:08
我还发现,如果我在 route.handler.promiseHandler 的 .catch() 中抛出错误,它将自动进入最终捕获。如果我返回错误,它将执行我想要的操作并处理整个数组。
2021-04-01 17:04:08

新答案

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

未来PromiseAPI

@shubham-jain.then().catch()Promise.resolve()将value传递给前者,而Promise.reject()将其传递给后者。你可以用它们的对象,例如:p.then(v => ({success: true, value: v})).catch(e => ({success: false, error: e}))
2021-03-19 17:04:08
@ArturKlesun 然后我们如何分类哪些Promise导致错误,哪些没有?
2021-03-29 17:04:08
为什么要过滤结果?如果你对结果做任何事情,那没有任何意义——你需要知道哪个返回值来自哪个Promise!
2021-03-29 17:04:08
虽然e不必是Error. 它可能是一个字符串,例如,如果有人像Promise.reject('Service not available').
2021-04-01 17:04:08

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

Promise.allSettled当所有输入Promise都得到解决时,会给你一个信号,这意味着它们要么被履行,要么被拒绝。这在您不关心 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']
})();

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

应该 s=>s.status
2021-03-20 17:04:08

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

这个想法是,您传递给的所有executeAllPromisesPromise 都将被包装到一个新的 Promise 中,该 Promise 将始终解析。新的 Promise 用一个有 2 个点的数组解析。第一个位置保存解析值(如果有),第二个位置保存错误(如果包装的 Promise 拒绝)。

作为最后一步,它会executeAllPromises累积包装的 Promise 的所有值,并返回带有数组 forresults和数组 for的最终对象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}`);
});

这可以更简单地完成。参见stackoverflow.com/a/36115549/918910
2021-04-07 17:04:08

Promise.allSettled

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

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));

填充物

@adirabargil 感谢您提供此信息 -这是用于此的polyfill
2021-03-22 17:04:08
请注意此处所述:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...它不支持 android 的 firefox
2021-04-06 17:04:08