我需要实现一个Promise.all
版本,它会接受一系列承诺,并像往常一样返回结果,并且还会解决所有承诺,就像Promise.settle
在{Bluebird
中所做的那样1}}库,除了我不能使用Bluebird
,并且必须仅依赖于标准的promise协议。
实施起来会非常复杂吗?或者在这里问一下如何实现它的想法太过分了?我真的希望不是,所以我问,如果有人可能之前实现它,分享如何做正确的想法。
这样做的前提是能够在调用完成后需要执行commit
/ rollback
的数据库事务中使用它,并且它仍然没有松散的承诺仍在尝试解决交易电话。
编辑:提供给另一个问题的链接非常有用,但它并不是对所提问题的完整答案。通用settle
是一个很好的例子,它有很多帮助,但它需要简化并包装成all
逻辑,以适应前面描述的事务场景。
答案 0 :(得分:7)
我认为jfriend的解决方案过于复杂,因为它构建在settle
之上,它运行信号量并执行许多奇怪的东西,而不是使用像.all
这样的内置原语。 / p>
相反,如果我们构建Bluebird的较新的reflect
原语(在本机承诺中实现它),我们可以获得更清晰的API和实现:
function reflect(promise){
return promise.then(x => ({state: "fulfilled", value: x}), // arrows, assume nodejs
e => ({state: "rejected" , value: e}));
}
除了反思之外,我们可以轻松地构建其他基元:
function settle(promises){
return Promise.all(promises.map(reflect)); // much cleaner
}
如果我们想等待,然后根据值解决/拒绝,那就是:
function allWait(promises){
return settle(promises).then(results => {
var firstFailed = results.find(r => r.state === "rejected");
if(firstFailed) throw firstFailed.value;
return results;
});
}
答案 1 :(得分:3)
在the other question的通用promiseSettle()
函数的基础上,您可以执行此操作并同时拥有通用settle()
类型函数和更具体的版本作为它的包装。这将为您提供执行大量.settle()
类型行为的通用功能,并具有您自己的特定风格,并根据需要构建其他特定风格:
所以,这里是通用promiseSettle()
,它返回所有承诺的状态,并且只有在完成所有传入的承诺后才会解决:
function promiseSettle(promises) {
return new Promise(function(resolve) {
var remaining = promises.length;
// place to store results in original order
var results = new Array(remaining);
function checkDone() {
if (--remaining === 0) {
resolve(results);
}
}
promises.forEach(function(item, index) {
// check if the array entry is actually a thenable
if (typeof item.then === "function") {
item.then(function(value) {
// success
results[index] = {state: "fulfilled", value: value};
checkDone();
}, function(err) {
// reject error
results[index] = {state: "rejected", value: err};
checkDone();
});
} else {
// not a thenable, just return the item itself
results[index] = {state: "fulfilled", value: item}
--remaining;
}
});
// special case for zero promises passed
if (remaining === 0) {
resolve(results);
}
});
}
而且,这里有一个包装器,可以为您提供特定的行为:
// Either fulfills with an array of results or
// rejects with the first error, but it does not do either
// until all promises have completed which makes it different than
// promise.all()
function promiseSettleAll(promises) {
return promiseSettle(promises).then(function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i].state !== "fulfilled") {
// reject with the first error found
throw results[i].value;
}
}
// all were successful, return just array of values
return results.map(function(item) {return item.value;});
});
}
答案 2 :(得分:0)
在所有研究,编写,测试和优化的最后,它变成了一个专注于此类事物的库(spex)。
具体来说,方法batch是实现所描述逻辑融合的方法。
我不是在这里重新发布its source code,因为它现在a lot more比问题中原先要求的那样。{/ p>