[英]Chain promises with Bluebird, returning whichever are solved
假设我有3个诺言:
这样: C -> B -> A
我希望能够返回已解决的问题,这意味着A,A和B或A,B和C。
我显然必须从解析A开始,但是如果我使用.then()
链接它们,则只要其中之一失败,整个链接就会失败。
如果我使用.some()
,则它期望一个Promises数组作为输入,因此在这种情况下它不起作用,因为.some()
不是彼此独立的。
谢谢。
并不需要任何特殊的内容, then
catch
(或您的Promise库中的等效内容)。
让承诺共享一个封闭的范围,在此范围内可以累积中间结果。
var results = {};
return doA().then(function(a) {
results.a = a;
return doB(a);
}).then(function(b) {
results.b = b;
return doC(b);
}).then(function(c) {
results.c = c;
return results;
}).catch(function(error) {
results.error = error;
return results;
});
对于可重用的方案,这是一种表驱动的方法,您只需传入函数和标签的列表,然后依次调用它们,就将前一个结果提供给下一个,直到一个被拒绝为止。
如果结果承诺得以实现,则解析的值是一个对象,其所有结果都位于所需的标记属性上。 如果任何一个操作被拒绝,则整体承诺将被拒绝,并且拒绝原因将是一个包含错误和错误之前收集的所有结果的对象:
function processList(list, initialArg) {
var results = {};
return sequence.reduce(function(p, item) {
return p.then(function(arg) {
// run the next item in the list and collect its result
return item.fn(arg).then(function(result) {
results[list[item.tag]] = result;
return result;
});
});
}, Promise.resolve(initialArg)).then(function() {
// return all results
return results;
}, function(err) {
// there was an error, return both the error and the results we have so far
throw {err, results};
});
}
// example usage
var sequence = [{fn: fnA, tag:"a"}, {fn: fnB, tag:"b"}, {fn: fnC, tag:"c"}];
processList(sequence, "whatever").then(function(results) {
// all results here
// results.a, results.b, results.c
}, function(errResults) {
var err = errResults.err;
var partialResults = errResults.results;
});
您还可以更改`processList()以始终解析并使用包含可以检查的err属性的对象进行解析。 哪种方法取决于您如何使用结果。
function processList(list, initialArg) {
var results = {};
return sequence.reduce(function(p, item) {
return p.then(function(arg) {
// run the next item in the list and collect its result
return item.fn(arg).then(function(result) {
results[list[item.tag]] = result;
return result;
});
});
}, Promise.resolve(initialArg)).then(function() {
// return all results
return {err:0, results: results};
}, function(err) {
// there was an error, return both the error and the results we have so far
return {err, results};
});
}
// example usage
var sequence = [{fn: fnA, tag:"a"}, {fn: fnB, tag:"b"}, {fn: fnC, tag:"c"}];
processList(sequence, "whatever").then(function(results) {
// promise always fulfills
// results.err tells you if there was an error or not
// results.a, results.b, results.c contain whatever results completed
});
由于这些都是承诺,因此您可以绝对同时同时操纵所有这三个对象,但是我不认为.some()
可以在这里完成工作。
具有一些错误处理的Promise.filter()
是一种解决方法:
var pA = asyncOperation();
var pB = pA.then(operationThatDependsOnA);
var pC = pB.then(operationThatDependsOnB);
// map pA, pB, and pC to promises that will resolve to null if their original promise fails
var safePromises = [pA, pB, pC].map(function (p) {
return p.catch(function () { return null; });
});
// filter the results to the ones that succeeded
Promise
.filter(safePromises, function (value) { return value !== null; })
.then(function (results) {
// results contains whichever promises succeeded, in the order A, B, C
console.log(results);
});
另一种选择是使用.reflect()
作为自己捕获错误的替代方法:
var pA = asyncOperation();
var pB = pA.then(operationThatDependsOnA);
var pC = pB.then(operationThatDependsOnB);
Promise
.filter(
[pA, pB, pC].map(function (p) { return p.reflect(); }),
function (inspection) { return inspection.isFulfilled(); }
)
.map(function (inspection) { return inspection.value(); })
.then(function (results) {
// results contains whichever promises succeeded, in the order A, B, C
console.log(results);
});
不需要任何特殊操作,如果在发生故障的过程中,您可以首先使用故障处理程序以您喜欢的方式处理错误,然后返回下一个承诺,例如;;
var p1 = new Promise((resolve,reject) => { var r = ~~(Math.random()*100); r > 49 ? resolve(r) : reject(r); }); var p2 = new Promise((resolve,reject) => { var r = ~~(Math.random()*100); r > 49 ? resolve(r) : reject(r); }); var p3 = new Promise((resolve,reject) => { var r = ~~(Math.random()*100); r > 49 ? resolve(r) : reject(r); }); p1.then(v => {console.log("p1 resolved to " + v); return p2;}, v => {console.log("p1 rejected by " + v); return p2;} ) .then(v => {console.log("p2 resolved to " + v); return p3;}, v => {console.log("p2 rejected by " + v); return p3;} ) .then(v => console.log("p3 resolved to " + v), v => console.log("p3 rejected by " + v) );
根据Roamer-1888对承诺相关性问题的评论,可以对上述代码进行如下修改,其中如果生成的随机值大于从先前承诺获得的值,则承诺可以解析;
function nextPromise(v){ var r = ~~(Math.random()*100); return new Promise((resolve, reject) => r > v ? resolve(r) : reject(r)); } var pA = new Promise((resolve,reject) => { var r = ~~(Math.random()*100); r > 49 ? resolve(r) : reject(r); }); pA.then(v => {console.log("pA resolved to " + v); return nextPromise(v);}, v => {console.log("pA rejected by " + v); return nextPromise(v);} ) .then(v => {console.log("pB resolved to " + v); return nextPromise(v);}, v => {console.log("pB rejected by " + v); return nextPromise(v);} ) .then(v => console.log("pC resolved to " + v), v => console.log("pC rejected by " + v) );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.