Promise = require 'bluebird'
cb = ->
console.log 'callback!'
p = Promise.resolve(5)
.cancellable()
.tap -> p.cancel()
setInterval(cb, 100)
仅cb
函数只调用一次。注释.tap -> p.cancel()
允许它重复运行。添加try
块无济于事。也许这是显而易见的事情,但我做了一些研究而无法找到解释。
答案 0 :(得分:4)
似乎从p.cancel()
处理程序返回tap
的值的行为导致bluebird进入某种无限循环。你永远不会看到第二个'callback!'
因为执行上下文在100毫秒之前停留在这个循环中。
我还远远没有理解这里发挥的所有因素(见下文),但看起来这可以通过不返回p.cancel()
来解决:
Promise = require 'bluebird'
cb = ->
console.log 'callback!'
p = Promise.resolve(5)
.cancellable()
.tap ->
p.cancel()
null
setInterval(cb, 100)
编辑:好的,看了几次来源并解开了我的大脑几次后,我认为可以归结为:
执行陷入无限循环,.cancel()
试图爬上承诺链:
while ((parent = promiseToReject._cancellationParent) !== undefined &&
parent.isCancellable()) {
promiseToReject = parent;
}
重点如下:
p.cancel()
返回p
。.tap()
返回一个承诺,只要从其处理程序返回的promise返回(如果它返回一个promise),它就会解析p
是.tap()
返回的承诺换句话说,p
是在p
结算后将解决的承诺。它是承诺链中的自己的祖先(至少,我认为是这样)。
当.cancel()
试图爬上承诺链以找到可取消的承诺时,它会发生在这种乱伦的关系中,并开始永远地进入圈内。
最后,CoffeeScript渴望将几乎所有内容都变成return
语句,这是一个不幸的结果。但我想,Bluebird可以通过某种方式检测到promise链中的循环,并防止在这里发生无限循环。
我已经在bluebird GitHub存储库中为此提交了issue,但正如随后的讨论所揭示的那样,.cancel()
的这种使用无论如何都没有任何意义。