gpt4 book ai didi

javascript - ES6 Promise.all() 错误句柄 - 是否需要 .settle()?

转载 作者:数据小太阳 更新时间:2023-10-29 04:04:12 25 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





Wait until all promises complete even if some rejected

(20 个回答)


6年前关闭。




假设我有一个处理两个 promise 的 Promise.all()。如果一个 promise 产生错误,但另一个 promise 解决了,我希望能够在 Promise.all() 解决后根据情况处理错误。

ES6 Promises 缺少解决方法,我假设是有充分理由的。但我不禁认为 .settle() 方法会让我更容易解决这个问题。

我是以错误的方式解决这个问题,还是用一种解决方法扩展 ES6 Promise 是正确的做法?

我如何考虑使用 .settle() 的一个例子:

Promise.all([Action1,Action2])
.settle(function(arrayOfSettledValues)
//if 1 failed but not 2, handle
//if 2 failed but not 1, handle
//etc....
)

最佳答案

Am I going about this the wrong way or is extending the ES6 Promises with a settle method the right thing to do here?



不能直接使用 Promise.all()生成 .settle()类型行为,无论是否拒绝,都会为您提供所有结果,因为 Promise.all()是“快速失败”,一旦第一个 promise 被拒绝,它就会返回,它只返回拒绝原因,没有其他结果。

所以,需要一些不同的东西。通常,解决该问题的最简单方法是添加 .then()任何操作的处理程序都会创建您的 promise 数组,以便它捕获任何拒绝并将它们转换为具有您可以测试的特定值的已履行 promise 。但是,这种类型的解决方案取决于实现,因为它完全取决于您返回的值类型,因此这并不完全是通用的。

如果你想要一个通用的解决方案,那么像 .settle()很有用。

您不能使用以下结构:
Promise.all([...]).settle(...).then(...);

注意(2019 年添加):Promise 标准工作似乎已选择 Promise.allSettled() 作为“类似定居”行为的标准实现。您可以在此答案的末尾看到更多信息。

因为 Promise.all()当你传递的第一个 promise 被拒绝时,它会拒绝并且它只返回那个拒绝。 .settle()逻辑工作如下:
Promise.settle([...]).then(...);

而且,如果您有兴趣,这里有一个相当简单的 Promise.settle() 实现。 :
// ES6 version of settle
Promise.settle = function(promises) {
function PromiseInspection(fulfilled, val) {
return {
isFulfilled: function() {
return fulfilled;
}, isRejected: function() {
return !fulfilled;
}, isPending: function() {
// PromiseInspection objects created here are never pending
return false;
}, value: function() {
if (!fulfilled) {
throw new Error("Can't call .value() on a promise that is not fulfilled");
}
return val;
}, reason: function() {
if (fulfilled) {
throw new Error("Can't call .reason() on a promise that is fulfilled");
}
return val;
}
};
}

return Promise.all(promises.map(function(p) {
// make sure any values are wrapped in a promise
return Promise.resolve(p).then(function(val) {
return new PromiseInspection(true, val);
}, function(err) {
return new PromiseInspection(false, err);
});
}));
}

在这个实现中, Promise.settle()将始终解析(从不拒绝),它使用 PromiseInspection 的数组解析允许您测试每个单独结果的对象,以查看它是解决还是拒绝,以及每个结果的值(value)或原因是什么。它通过附加 .then() 来工作传入的每个 Promise 的处理程序,处理来自该 Promise 的解析或拒绝,并将结果放入 PromiseInspection对象然后成为 promise 的已解决值。

然后,您将像这样使用此实现;
Promise.settle([...]).then(function(results) {
results.forEach(function(pi, index) {
if (pi.isFulfilled()) {
console.log("p[" + index + "] is fulfilled with value = ", pi.value());
} else {
console.log("p[" + index + "] is rejected with reasons = ", pi.reason());
}
});
});

仅供引用,我写了另一个版本的 .settle我自己调用 .settleVal()当您不需要实际的拒绝原因时,我经常发现它更容易使用,您只想知道给定的数组插槽是否被拒绝。在此版本中,您传入一个默认值,该值应替换任何被拒绝的 promise 。然后,您只得到一个返回值的平面数组,以及任何设置为默认值的被拒绝的值。例如,您通常可以选择 rejectValnull0""{}它使结果更容易处理。这是功能:
// settle all promises.  For rejected promises, return a specific rejectVal that is
// distinguishable from your successful return values (often null or 0 or "" or {})
Promise.settleVal = function(rejectVal, promises) {
return Promise.all(promises.map(function(p) {
// make sure any values or foreign promises are wrapped in a promise
return Promise.resolve(p).then(null, function(err) {
// instead of rejection, just return the rejectVal (often null or 0 or "" or {})
return rejectVal;
});
}));
};

然后你像这样使用它:
Promise.settleVal(null, [...]).then(function(results) {
results.forEach(function(pi, index) {
if (pi !== null) {
console.log("p[" + index + "] is fulfilled with value = ", pi);
}
});
});

这不是 .settle() 的完全替代品因为有时您可能想知道它被拒绝的实际原因,或者您无法轻松区分被拒绝的值和未拒绝的值。但是,我发现超过 90% 的时间,这更容易使用。

这是我对 .settle() 的最新简化留下 instanceof Error在返回数组中作为区分解析值和拒绝错误的方法:
// settle all promises.  For rejected promises, leave an Error object in the returned array
Promise.settleVal = function(promises) {
return Promise.all(promises.map(function(p) {
// make sure any values or foreign promises are wrapped in a promise
return Promise.resolve(p).catch(function(err) {
let returnVal = err;
// instead of rejection, leave the Error object in the array as the resolved value
// make sure the err is wrapped in an Error object if not already an Error object
if (!(err instanceof Error)) {
returnVal = new Error();
returnVal.data = err;
}
return returnVal;
});
}));
};

然后你像这样使用它:
Promise.settleVal(null, [...]).then(function(results) {
results.forEach(function(item, index) {
if (item instanceof Error) {
console.log("p[" + index + "] rejected with error = ", item);
} else {
console.log("p[" + index + "] fulfilled with value = ", item);
}
});
});

这可以完全替代 .settle()对于所有情况,只要 instanceof Error从来都不是你的 promise 的解决值(value)(它真的不应该)。

promise 标准努力

截至 2019 年,似乎 .allSettled() 正在成为这种行为的标准。而且,这是一个 polyfill:
if (!Promise.allSettled) {
Promise.allSettled = function(promises) {
let wrappedPromises = Array.from(promises).map(p =>
this.resolve(p).then(
val => ({ state: 'fulfilled', value: val }),
err => ({ state: 'rejected', reason: err })
)
);
return this.all(wrappedPromises);
}
}

用法是这样的:
let promises = [...];    // some array of promises, some of which may reject
Promise.allSettled(promises).then(results => {
for (let r of results) {
if (r.state === 'fulfilled') {
console.log('fulfilled:', r.val);
} else {
console.log('rejected:', r.err);
}
}
});

请注意 Promise.allSettled()本身总是解决,从不拒绝后续的 .then()处理程序可以抛出或返回被拒绝的 promise 以使整个链拒绝。

截至 2019 年 6 月,当前桌面版 Chrome 浏览器中还没有此功能,但计划在即将发布的版本中(例如 2019 年晚些时候)。

关于javascript - ES6 Promise.all() 错误句柄 - 是否需要 .settle()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36605253/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com