2015-03-02 32 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