为什么在callback函数setInterval中取消蓝鸟承诺?

Promise = require 'bluebird' cb = -> console.log 'callback!' p = Promise.resolve(5) .cancellable() .tap -> p.cancel() setInterval(cb, 100) 

cb函数只能被调用一次。 注释.tap -> p.cancel()允许它重复运行。 添加一个try块没有帮助。 也许这是显而易见的,但我做了一些研究,找不到解释。

似乎从tap处理程序返回p.cancel()的值导致蓝鸟进入某种无限循环。 你永远不会看到第二个'callback!' 因为执行上下文在100 ms之前停留在此循环中。

我还远远没有理解所有的因素(见下文),但是看起来这可以通过不返回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()返回一个承诺,parsing每当从它的处理程序返回的承诺解决(如果它返回一个承诺)
  • p.tap()返回的承诺

换句话说, ppparsing后的一个承诺。 这是承诺链中的自己的祖先(至less我是这样认为的)。

.cancel()试图爬上承诺链来寻找一个可以取消的承诺时,它发生在这个乱伦的关系上,并且永远地开始.cancel()

最后,这是CoffeeScript渴望将几乎所有事情都变成return声明的不幸后果。 但是我可以想象,Bluebird可以通过某种方式检测承诺链中的循环,并防止在这里发生无限循环。

我已经在bluebird GitHub仓库上提出了这个问题 ,但是随后的讨论揭示,这个.cancel()根本没有任何意义。