【问题标题】: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 操作

标签: javascript promise bluebird


【解决方案1】:

我完全确定你在问什么。

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

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

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

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

    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 添加加入时,这绝对是我的想法。我认为这是一个不错的风格
    • 很高兴听到,我真的很喜欢。
    猜你喜欢
    • 2014-08-16
    • 2015-11-26
    • 2015-07-08
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    相关资源
    最近更新 更多