2016-04-20 35 views
7

延遲執行功能(例如在自定義事件處理中)是JavaScript中的常見模式(請參閱here)。它曾經是使用setTimeout(myFunc,0)是唯一的方法來做到這一點,但承諾現在有一個替代方案:Promise.resolve().then(myFunc)使用promises或setTimeout決定延遲函數的調用順序是什麼?

我假設這些幾乎都做同樣的事情,但是在包含自定義事件的庫上工作時,我想我會發現是否有差異,因此我將以下塊放入節點中:

var logfn=function(v){return function(){console.log(v)}}; 

setTimeout(logfn(1),0); 
Promise.resolve().then(logfn(2)); 
logfn(3)(); 

我期待看到控制檯3,1,2,而是我看到了3,2,1。所以換句話說,承諾不等同於使用setTimeout和散發出來的塊的第一個。至少在Node中。

我在Chrome和Firefox中重複了測試,結果相同,但在Edge中出現爲3,1,2。我還希望非本機諾言庫在引擎蓋下使用setTimeout,這樣會出來與Edge相同。

什麼決定了這些調用順序的解決?這些不同的環境使用什麼模型來確定執行順序?以上任何情況是否代表標準或非標準行爲?

PS我沒有建議依靠任何這種保持一致,我只是好奇。


下面給出的答案後,我指出了正確的方向,並且在下面的評論中提到簡單地說,我發現了一個很好的article by Jake Archibald完整的答案(幾乎等同於我上面的代碼的例子),我儘管我會加在這裏,而不是將它埋在評論中。

+0

FWIW,沒有什麼是* *保證異步執行任何特定的順序。你永遠不應該試圖首先依靠執行順序。這使得這個問題成爲關於實現細節的有趣討論,但實際上並沒有實際意義。 – deceze

+0

也許,但我傾向於發現,我的編碼提高得越多,我越理解它是如何掛在一起的,即使是間接的。在仔細研究下面的答案之後,我也發現了幾乎完全是我上面的例子以及完整的解釋[這裏](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)。考慮到所有這些,我可以肯定的看到,推動微任務或macrotask隊列的具體情況可能是適當的,儘管需要確保只有macrotasks可用時沒有任何事情被破壞 –

回答

1

LL取決於resolve()是如何在內部實現 - 也許你觀察setTimeout(fn, 0)和邊緣的實現之間的差異爲setImmediate(fn)

請考慮文章 - http://www.mattgreer.org/articles/promises-in-wicked-detail/resolve方法是如何實現的方式。 https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/dev-guide/performance/efficient-script-yielding/和多一個環節 - -

function resolve(value) { 
    // force callback to be called in the next 
    // iteration of the event loop, giving 
    // callback a chance to be set by then() 
    setTimeout(function() { 
     callback(value); 
    }, 1); 
} 

比一些explenations可以在priority between setTimeout and setImmediate

從微軟的文檔中找到setImmediate method

+2

感謝您的文章鏈接和參考'setImmediate'這對我來說是新的。看着這些讓我對[[microtask和macrotask事件隊列](http:// stackoverflow)之間的差異導致了這個前面的stackoverflow答案的polyfill [setImmediate](https://github.com/YuzuJS/setImmediate)。com/a/25933985/4098951),這似乎解釋了發生了什麼。我猜Chrome等人使用microtask事件隊列來執行承諾,'setTimeout'在macrotask隊列上進行。邊緣也許沒有這樣的區別。 –