2014-03-26 160 views
2

牢記這樣一句話:嵌套承諾處理

一旦對象已經進入解決或拒絕狀態,它停留在該狀態。回調仍然可以添加到解決或拒絕延期 - 他們將立即執行。

http://api.jquery.com/jQuery.Deferred/

你會想到這個代碼產生什麼:

var d = $.Deferred(); 

var a = function() { 
    d.done(function() { 
     console.log('inner'); 
    }); 

    console.log('outer'); 
}; 

d.done(a); 

d.resolve(); 

我期待它是inner,然後outer。而不是我檢查的任何jQuery版本的情況。

你認爲這是一個錯誤還是我從描述中忽略了一點?

相應的jsfiddle:http://jsfiddle.net/U8AGc/

UPD:一些背景的問題:我預計a方法同樣的行爲,無論它是如何準確地調用:就像一個a()d.done(a)

+2

這只是一個不遵循Promises/A +的怪事:-) – Bergi

回答

3

我想到一個方法,同樣的行爲,無論它是如何準確地調用:只是作爲一個()或d.done(一)

編號d.done(a)並不總是立即呼叫a() - 當d尚未解決時,最顯着。

Promises/A+通過要求處理程序始終異步觸發解決了這種模糊性問題,即在這裏您可以預期在每種情況下outer都會先於inner

我期待它是inner,然後outer

這通過jQuery.Callbacks,其具有用於不立即執行的處理程序內的處理程序的明確firing flag防止;相反,添加的處理程序會附加到隊列中。這也是防止堆棧溢出的一個功能,它通過「鎖定」它簡化了fire函數。

您認爲這是一個錯誤還是我從描述中忽略了一點?

我不考慮承諾/ A +錯誤:-)描述只是沒有處理 - 很少見 - 特殊情況。

我想說的一點是,在解決deferreds 處理器仍然會自動連分辨率後執行,通過「立即」他們並不一定意味着「從.done中同步」,而是「馬上,如儘快「。

+0

「d.done(a)並不總是立即調用一個()」---這就是引用的文檔所述。 「回調仍然可以添加到解決或拒絕延期 - 他們將立即**執行**。」 – zerkms

+0

是的,但它沒有說明當你將回調添加到延期*時,會發生什麼情況*目前正在解決或拒絕* :-) – Bergi

+0

是的,但這是一個致命的差異,必須提到。雖然:-) – zerkms

1

這裏是什麼發生:

var a = function() { 
    // the function logging 'inner' is *added* to the call stack 
    d.done(function() { 
     console.log('inner'); 
    }); 
    // 'outer' is logged 
    console.log('outer'); 
}; 
// `a` has finished executing, then the anonymous function logs 'inner' 

我在堆棧跟蹤*中添加了一個日誌* your JSFiddle - 你可以看到函數a無法在記錄的anon函數中找到inner - jQuery在a完成執行後調用它。

jQuery源代碼中的相關行是found here(注意它正在添加到隊列中)。

*跟蹤代碼here