繁体   English   中英

与Bluebird达成的连锁承诺,无论哪种解决方案都归还

[英]Chain promises with Bluebird, returning whichever are solved

假设我有3个诺言:

  • 承诺A
  • 承诺B取决于A的输出
  • 承诺C取决于B的输出

这样: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM