我可以用 bluebird Promises 提前打破链条吗?
Posted
技术标签:
【中文标题】我可以用 bluebird Promises 提前打破链条吗?【英文标题】:Can I break a chain early with bluebird Promises? 【发布时间】:2015-04-18 18:42:06 【问题描述】:我不一定想出错,但我有:
getFromDb().then (tradeData) ->
if not tradeData
# DO NOT CONTINUE THE CHAIN
else
getLatestPrice tradeData
.then (latestPrice) ->
...
.then ->
...
.then ->
...
.catch (err) ->
next err
如果没有 tradeData,我有什么方法可以中止链吗?
【问题讨论】:
你不能从 bb 中的then
明确地返回一个新的承诺(一个适当的解决失败的承诺)吗?如果只是“破坏链条”不起作用那么..它根本不是链条。
你会想看看Break promise chain and call a function based on the step in the chain where it is broken和Handling multiple catches in promise chain
【参考方案1】:
我只是想知道为什么不利用您可以throw
随心所欲的事实,而不仅仅是instanceof Error
。这样做被认为是不好的做法?在我看来,这取决于您要完成的工作。 Promise 链可能会因各种原因而中断,但通常这两者会分为两组。 Classic error occur
和 early break in chain
需要。从逻辑上讲,第二个不能被视为应该是instance of Error
。
const handleError = (err) =>
...
const skip = (reason, ..., ...) =>
/**
* construct whatever you like
* just for example here return reason
*/
return reason
Promise.resolve()
.then(() =>
if (iShouldEndChainEarlier)
throw skip('I would like to end chain earlier')
return asyncOperation1()
)
.then(results =>
...
return asyncOperation2(results)
)
.then(... =>
...
)
.catch(interrupt =>
if (interrupt instanceof Error)
return handleError(interrupt)
/**
* Handle breaking promise chain earlier
* having interrupt reason in scope
*/
)
如果从逻辑上讲,链的早期中断可以被视为错误(完全可能是这种情况),您可以创建自定义错误并在catch
块中区分两者。所以只是说在处理承诺链中可能发生的任何中断时可以考虑另一种方法。
我们可以争辩说这是否可以被视为反对节点中的first error pattern
。如果有错误,最好的做法是调用像callback(err)
这样的回调,其中err
真的应该是instanceof Error
,否则callback(null, data)
。但另一方面,请记住 .catch(fn)
对我来说只是 then(undefined, onRejected)
的糖,它似乎足以根据您所处的情况处理 onRejected
参数。
【讨论】:
【参考方案2】:虽然是公认的答案,但我想告诉所有的谷歌人,“break()”函数已更改为“cancel()”
使用这样的东西:
p = getFromDb().then (tradeData) ->
if not tradeData
send("no data");
p.cancel(); // Look Here!!!!!!!!!!!!!!!!
else
getLatestPrice tradeData
.then (latestPrice) ->
...
.then ->
...
.then ->
...
.catch (err) ->
next err
在此之前,请确保在配置中添加以下行:
Promise.config(
cancellation: true
);
【讨论】:
【参考方案3】:getFromDb().then (tradeData) ->
if tradeData
getLatestPrice tradeData ->
.then (latestPrice) ->
...
.then ->
...
.then ->
...
.catch (err) ->
next err
else
getSomethingElse ->
send("no data")
在 3.0 中,您将能够做到这一点:
p = getFromDb().then (tradeData) ->
if not tradeData
send("no data");
p.break()
else
getLatestPrice tradeData
.then (latestPrice) ->
...
.then ->
...
.then ->
...
.catch (err) ->
next err
【讨论】:
如果我想实现额外的分支逻辑怎么办?例如,如果有tradeData
,则执行某些步骤,如果没有,是否执行其他步骤?
@Shamoon 使用else
@Esailija:为什么?我希望您还没有将goto
构建到承诺链中?编辑:糟糕,我现在已经阅读了您的答案。当然,取消自己并不那么清楚:-)
@Bergi 顺便说一句,在 3.0 中,您可以使用对象属性作为错误谓词,这样您就可以拥有 throw label: "no data"
,然后是 .catch(label: "no data", function(e))
- 但在这种特殊情况下,我仍然会更喜欢 break,因为它应该是这里发生的事情非常直观。
@Esailija : 在 bluebird API bluebirdjs.com/docs/api-reference.html987654321@ 中没有提到 break以上是关于我可以用 bluebird Promises 提前打破链条吗?的主要内容,如果未能解决你的问题,请参考以下文章
使用Bluebird.mapSeries顺序处理一系列API调用