处理嵌套承诺的最佳方法(蓝鸟)[重复]

Posted

技术标签:

【中文标题】处理嵌套承诺的最佳方法(蓝鸟)[重复]【英文标题】:Best way to handle nested Promises (bluebird) [duplicate] 【发布时间】:2014-12-05 23:14:30 【问题描述】:

我在下面有以下承诺链,它看起来很混乱(每个_create* 函数都返回一个承诺):

return new Promise(function (resolve, reject) 
      _this.database.transaction(function (t) 
        _this._createExternalAccount(payment, t)
          .then(function (externalAccount) 
            return _this._createExternalTransaction(externalAccount, payment, t)
              .then(function (externalTransaction) 
                return _this._createAddress(externalAccount, payment, t)
                  .then(function (address) 
                    return _this._createTransaction(address, payment, t)
                      .then(function (transaction) 
                        return _this._createGatewayTransaction(externalTransaction, transaction, payment, t)
                          .then(function (gatewayTransaction) 
                            t.commit();
                            resolve(bridgePayment);
                          );
                      );
                  );
              );
          )
          .error(function (bridgePayment) 
            t.rollback();
            reject(bridgePayment);
          );
      );

我知道我可以使用 Promise 函数,例如 all()join(),但这些函数似乎可以同时运行这些函数,而我不能这样做,因为持久化到某些表需要来自以前持久化表的字段。我希望有某种方法可以让我执行以下操作,但我似乎无法找到方法:

Promise.all(_this._createExternalAccount(payment, t), _this._createExternalTransaction(externalAccount, payment, t), _this._createAddress(externalAccount, payment, t))
    .then(function(externalAccount, externalTransaction, address) 
        // do logic
    );

【问题讨论】:

您可能想探索链接:p.then().then().then().then() 而不是嵌套。 检查 Bluebird .map() 你可以通过 concurrency: N 所以它一次只执行 N 操作 【参考方案1】:

我完全确定你在问什么。

    如果您想按顺序运行一组 Promise,可以使用 this answer

    需要注意的重要一点是它不是一系列承诺。这是一组做出承诺的函数。这是因为 Promise 会立即执行,所以在需要之前您无法创建 Promise。

    如果您不想将它们放入数组中,虽然正常的事情只是正常链接它们。

    再次让一​​堆函数返回承诺的最简单方法。那你就

    var p = firstFunctionThatReturnsAPromise()
    .then(secondFunctionThatReturnsAPromise)
    .then(thirdFunctionThatReturnsAPromise)
    .then(fourthFunctionThatReturnsAPromise)
    

    您可以轻松嵌套它们

    function AOuterFunctionThatReturnsAPromise()          
        var p = firstFunctionThatReturnsAPromise()
                .then(secondFunctionThatReturnsAPromise)
                .then(thirdFunctionThatReturnsAPromise)
                .then(fourthFunctionThatReturnsAPromise);
        return p;
    ;
    

    现在,外部函数只是另一个返回承诺的函数,这意味着你 可以应用与内部函数相同的模式。

    如果这些当然可以内联

    var p = function() 
      return new Promise(resolve, reject) 
        DoSomethingAsync(function(err, result) 
          if (err) 
            reject();
           else 
            resolve(result);
        ;
      ;
    ).then(function() 
      return new Promise(resolve, reject) 
        DoSomethingAsync(function(err, result) 
          if (err) 
            reject(err);
           else 
            resolve(result);
        ;
      ;
    ).then(function() 
      var err = DoSomethingNotAsync();
      if (err) 
         return Promise.reject(err);
       else 
         return Promise.resolve();
      
    );
    

    等等……

【讨论】:

【参考方案2】:

就个人而言,当依赖关系变得混乱时,我更喜欢以下方法:

var externalAccount     = Promise.join(payment, t,                                   createExternalAccount),
    externalTransaction = Promise.join(externalAccount, payment, t,                  createExternalTransaction),
    address             = Promise.join(externalAccount, payment, t,                  createAddress),
    transaction         = Promise.join(address, payment,                             createTransaction),
    gatewayTransaction  = Promise.join(externalTransaction, transaction, payment, t, createGatewayTransaction);

让一切变得更干净,尽管这是风格问题。

如果你想在获得gatewayTransaction 的值后做某事(当然是异步的),你可以:

gatewayTransaction
    .then(function (val) 
        // do stuff
    )
    .catch(function (err) 
        // do stuff
    );

这里有一个你应该注意的微妙陷阱。定义承诺的顺序不一定是调用函数的顺序。这就是依赖项的样子:

externalAccount -----> externalTransaction -----> gatewayTransaction
                |--> address --> transaction --|

虽然这对性能有好处,但您可能希望使整个事情顺序化(就像您的回调金字塔一样)。在这种情况下,你可以写:

var externalAccount     = Promise.join(payment, t,                                       createExternalAccount),
    externalTransaction = Promise.join(externalAccount, payment, t,                      createExternalTransaction),
    address             = Promise.join(externalAccount, payment, t, externalTransaction, createAddress),
    transaction         = Promise.join(address, payment,                                 createTransaction),
    gatewayTransaction  = Promise.join(externalTransaction, transaction, payment, t,     createGatewayTransaction);

通过将externalTransaction 添加到address 的依赖项(即使它的值不需要),您可以强制它是顺序的。

【讨论】:

当我们与 Gorgi 和 Petka 讨论向 Bluebird 添加加入时,这绝对是我的想法。我认为这是一个不错的风格 很高兴听到,我真的很喜欢。

以上是关于处理嵌套承诺的最佳方法(蓝鸟)[重复]的主要内容,如果未能解决你的问题,请参考以下文章

蓝鸟嵌套承诺与每个/传播

猫鼬静态方法返回一个蓝鸟承诺

将已解决的承诺值传递到最终的“then”链的最佳方法是啥[重复]

处理 BigQuery 中未嵌套记录导致的重复行的最佳做法?

干净的代码和嵌套的承诺 [重复]

使用蓝鸟承诺的while循环