Bluebird的链承诺,返回哪个被解决

时间:2016-07-16 13:48:32

标签: javascript promise bluebird

假设我有3个承诺:

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

这样:C -> B -> A

我希望能够返回已解决的内容,即A,A和B,或A和B以及C.

我显然必须首先解析A,但如果我使用.then()链接它们,只要其中一个失败,整个链就会失败。

如果我使用.some(),它需要一个Promise数组作为输入,因此在这种情况下它不起作用,因为承诺不是彼此独立的。

谢谢。

4 个答案:

答案 0 :(得分:2)

不需要任何特殊内容,只需thencatch(或诺言库中的等效内容)。

让承诺共享一个封闭范围,可以累积中间结果。

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;
});

答案 1 :(得分:1)

对于可重用的方案,这里是一个表驱动的方法,你只需传入一个函数和标签列表,然后一个接一个地调用它们,将前一个结果提供给下一个结果直到一个拒绝。

如果生成的承诺满足,则解析的值是一个对象,其中包含所需标记属性的所有结果。如果任何操作拒绝,则整体承诺将拒绝,拒绝原因将是包含错误和错误之前收集的所有结果的对象:

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()更改为始终解析并解析包含您可以检查的错误属性的对象。哪种方式取决于您希望如何使用结果。

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
});

答案 2 :(得分:0)

由于这些是承诺,你绝对可以同时操纵这三个,但我不认为.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);
    });

答案 3 :(得分:0)

不需要任何特殊功能,如果发生故障,您可以先使用故障处理程序以您喜欢的方式处理错误,然后返回下一个承诺,例如;



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关于promise依赖关系的评论,如果生成的随机值大于从前一个promise中获得的值,则promise可以如下修改上述代码;



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)
       );