处理嵌套Promise的最佳方法(bluebird)

时间:2014-10-10 17:52:36

标签: javascript promise bluebird

我在下面有以下承诺链,它看起来很混乱(每个_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);
          });
      });

我知道我可以使用像all()join()这样的Promise函数,但这些函数似乎同时运行我无法做到的函数,因为持久化到某些表需要来自先前持久表的字段。我希望有一些方法让我做以下的事情,但我似乎无法找到如何:

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

2 个答案:

答案 0 :(得分:6)

我确切地知道你在问什么但是。

  1. 如果您想按顺序运行一系列承诺this answer

    重要的是要注意的是它不是一系列的承诺。它是一系列承诺的功能。这是因为承诺会立即执行,因此您无法在需要之前创建承诺。

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

    等...

答案 1 :(得分:3)

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

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

你应该知道这里有一个微妙的陷阱。定义promise的顺序不一定是调用函数的顺序。这就是依赖关系的样子:

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的依赖项(即使不需要它的值),您可以强制它是顺序的。