2015-03-02 80 views
1
Promise = require 'bluebird' 

cb = -> 
    console.log 'callback!' 
    p = Promise.resolve(5) 
    .cancellable() 
    .tap -> p.cancel() 

setInterval(cb, 100) 

cb函数只能调用一次。注释掉.tap -> p.cancel()允许它重复运行。增加一个try块没有帮助。也许这是显而易见的,但我做了一些研究,找不到解释。为什么在回调停止setInterval中取消蓝鸟承诺?

+0

我刚刚运行一个简单的测试,并从'setInterval()'回调中抛出一个异常不会停止计时器,因此看起来并不相关。 – jfriend00 2015-03-02 16:11:46

回答

4

似乎从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) 

编辑:好,照顾在源和unknotting我的大脑了几下,我认为它归结为:

执行被卡在这里了无限循环,其中.cancel()试图爬上承诺链:

while ((parent = promiseToReject._cancellationParent) !== undefined && 
    parent.isCancellable()) { 
    promiseToReject = parent; 
} 

的要点如下:

  • p.cancel()回报p
  • .tap()返回解析时的承诺从它的处理程序做出决议返回(如果它返回一个承诺)
  • p是承诺,.tap()回报

换句话说,p是一种承诺,将承诺在p解决后解决。它是承诺链中的自己的祖先(至少,我认为是这样)。

.cancel().cancel()试图爬上承诺链来寻找一个可以取消的承诺时,它发生在这个乱伦关系上,并开始永远循环。最后,这是CoffeeScript渴望将几乎所有东西都变为return声明的一个不幸后果。但我可以想象,Bluebird可以通过某种方式检测承诺链中的循环,并防止发生无限循环。

我已经在蓝鸟GitHub存储库上提交了一个issue,但是随后的讨论揭示,.cancel()的这种使用根本没有任何意义。

+0

有趣!感谢您的分析。其实蓝鸟可以检测到循环。如果你在一个圆圈中返回一个承诺('p = Promise(5).then - > p'),它将触发一个'TypeError:循环承诺解析链'。我想我会提出一个功能要求。 – 2015-03-02 23:27:32

+0

我看到你比我领先一步。 – 2015-03-02 23:30:08

+0

我认为你应该把这个报告为Bluebird的一个bug。 – Bergi 2015-03-03 12:40:40