处理嵌套承诺的最佳方法(蓝鸟)[重复]
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”链的最佳方法是啥[重复]