假设我有一组promise正在发出网络请求,其中一个将失败:

// http://does-not-exist will throw a TypeError
var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]

Promise.all(arr)
  .then(res => console.log('success', res))
  .catch(err => console.log('error', err)) // This is executed   

假设我想要等到所有这些都完成,不管是否有一个失败了。可能有一个资源的网络错误,我可以没有,但如果我能得到,我想在继续之前。我想优雅地处理网络故障。

因为承诺。所有这些都没有留下任何空间,在不使用承诺库的情况下,处理这个问题的推荐模式是什么?


当前回答

这应该与Q的做法一致:

if(!Promise.allSettled) {
    Promise.allSettled = function (promises) {
        return Promise.all(promises.map(p => Promise.resolve(p).then(v => ({
            state: 'fulfilled',
            value: v,
        }), r => ({
            state: 'rejected',
            reason: r,
        }))));
    };
}

其他回答

与其拒绝,不如用一个对象来解决。 当你实现承诺时,你可以这样做

Const promise = arg => { 返回新的承诺((resolve, reject) => { setTimeout(() => { 尝试{ If (arg != 2) 返回解析({success: true, data: arg}); 其他的 抛出新的错误(arg) }捕捉(e) { 返回解析({success: false, error: e, data: arg}) } }, 1000); }) } Promise.all([1、2、3、4、5)。Map (e => promise(e)))。然后(d => console.log(d))

有一个完成的提议,一个函数,可以完成这个本机,在香草Javascript:承诺。allsettle已经进入了第4阶段,在ES2020中正式发布,并在所有现代环境中实现。它和另一个答案中的反射函数很相似。这里有一个例子,来自提案页面。以前,你必须这样做:

function reflect(promise) {
  return promise.then(
    (v) => {
      return { status: 'fulfilled', value: v };
    },
    (error) => {
      return { status: 'rejected', reason: error };
    }
  );
}

const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.all(promises.map(reflect));
const successfulPromises = results.filter(p => p.status === 'fulfilled');

使用的承诺。取而代之的是,上述内容将等价于:

const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.allSettled(promises);
const successfulPromises = results.filter(p => p.status === 'fulfilled');

那些使用现代环境的人不需要任何库就可以使用这种方法。在这些情况下,下面的代码段应该可以正常运行:

Promise.allSettled ([ Promise.resolve (' a '), Promise.reject (b) ]) 不要犹豫(console.log);

输出:

[
  {
    "status": "fulfilled",
    "value": "a"
  },
  {
    "status": "rejected",
    "reason": "b"
  }
]

对于较老的浏览器,这里有一个符合规范的填充。

我不知道你在使用哪个承诺库,但大多数都有类似allsettle的东西。

编辑:好的,因为你想使用普通的ES6而没有外部库,没有这样的方法。

换句话说:您必须手动遍历承诺,并在所有承诺解决后立即解决新的组合承诺。

我最近建立了一个库,可以满足你的需要。它并行执行承诺,如果一个承诺失败,进程继续,最后它返回一个包含所有结果的数组,包括错误。

https://www.npmjs.com/package/promise-ax

我希望这对某些人有帮助。

const { createPromise } = require('promise-ax');
const promiseAx = createPromise();
const promise1 = Promise.resolve(4);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, new Error("error")));
const promise3 = Promise.reject("error");
const promise4 = promiseAx.resolve(8);
const promise5 = promiseAx.reject("errorAx");
const asyncOperation = (time) => {
    return new Promise((resolve, reject) => {
        if (time < 0) {
            reject("reject");
        }
        setTimeout(() => {
            resolve(time);
        }, time);
    });
};
const promisesToMake = [promise1, promise2, promise3, promise4, promise5, asyncOperation(100)];
promiseAx.allSettled(promisesToMake).then((results) =>   results.forEach((result) => console.log(result)));
// Salida esperada:
// 4
// Error: error
// error
// 8
// errorAx
// 100

我只是想要一个完全复制ES2020行为的填充,因为我被锁定在比12.9更早的节点版本(当Promise。allsettle出现了),不幸的是。所以不管怎样,这是我的版本:

const settle = (promise) => (promise instanceof Promise) ?
  promise.then(val => ({ value: val, status: "fulfilled" }),
               err => ({ reason: err, status: "rejected" })) :
  { value: promise, status: 'fulfilled' };

const allSettled = async (parr) => Promise.all(parr.map(settle));

它处理承诺值和非承诺值的混合数组,就像ES版本一样。它返回与原生版本相同的{status, value/reason}对象数组。