2014-10-10 2 views
11

У меня есть следующее обещание цепь ниже, и это, кажется, довольно грязные (каждый _create * Функция возвращает обещание):Лучшего способ справиться с вложенным Promises (Bluebird)

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 I могут использовать как 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 
    }); 
+3

Вы можете исследовать цепочки...(), а не вложенности. – jfriend00

+0

Check Bluebird '.map()' вы можете передать '{concurrency: N}', поэтому он выполняет только операции «N» за один раз – aarosil

ответ

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

    Теперь, когда внешняя функция является просто еще одна функция, возвращающая обещание, которое означает, что вы можете применить той же схеме, как и внутренних функций.затем `p.then(), а затем(), а затем():

    Если конечно это могут быть инлайн

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

    и т.д ...

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 «s (асинхронно, конечно), вы можете просто:

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 «s зависимостей (даже если его значение не требуется), вы можете заставить его быть последовательным.

+2

Это определенно то, что я имел в виду, когда мы обсуждали добавление соединения к Bluebird с Gorgi и Petka , Я думаю, что это хороший стиль. –

+0

Рад слышать, мне это очень нравится. – liadmat

Смежные вопросы