為什麼 Promise 比setTimeout() 快?下面這篇文章就來跟大家分析一下原因。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。
相關推薦:《javascript影片教學》
我們來做個實驗。哪個執行得更快:立即解決的Promise 還是立即setTimeout
(也就是0毫秒的setTimeout)?
Promise.resolve(1).then(function resolve() { console.log('Resolved!'); }); setTimeout(function timeout() { console.log('Timed out!'); }, 0); // 'Resolved!' // 'Timed out!'
promise.resolve(1)
是一個靜態函數,它傳回一個立即解析的promise
。 setTimeout(callback, 0)
以0毫秒
的延遲執行回呼函數。
我們可以看到先列印'Resolved!'
,再列印Timeout completed!
,立即解決的promise 比立即setTimeout
#更快。
是因為Promise.resolve(true).then(...)
在setTimeout(..., 0)
之前被呼叫了,所以Promise 過程會更快嗎?公平的問題。
所以,我們稍微改變一下實驗條件,然後先呼叫setTimeout(..., 0)
:
setTimeout(function timeout() { console.log('Timed out!'); }, 0); Promise.resolve(1).then(function resolve() { console.log('Resolved!'); }); // 'Resolved!' // 'Timed out!'
setTimeout(..., 0 )
在Promise.resolve(true).then(...)
之前被呼叫。但,先印出Resolved!
在印出'Timed out!'
。
這是為啥呢?
與非同步 JS 相關的問題可以透過研究事件循環來回答。我們回顧一下非同步 JS 工作方式的主要組成部分。
[外鏈圖片轉存失敗,來源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Lt9zVHTf-1611275604640)(/img/bVcMQaI)]
#呼叫堆疊是一個LIFO(後進先出)結構,它儲存在程式碼執行期間所建立的執行上下文。簡單地說,呼叫堆疊執行這些函數。
Web api是非同步操作(fetch 請求、promise、計時器)及其回呼等待完成的地方。
**task queue (任務佇列)是一個FIFO(先進先出)**結構,它保存準備執行的非同步操作的回呼。例如,逾時的setTimeout()
的回呼函數或準備執行的點選按鈕事件處理程序都會在任務佇列中排隊。
**job queue (作業佇列)**是一個FIFO(先入先出)結構,它保存準備執行的promise
的回呼。例如,已完成的承諾的resolve
或reject
回呼被排在作業佇列中。
最後,事件循環永久監聽呼叫堆疊是否為空。如果呼叫堆疊為空,則事件循環查看作業佇列或任務佇列,並將準備執行的任何回呼分派到呼叫堆疊中。
我們從事件循環的角度來看這個實驗,我將對程式碼執行進行一步一步的分析。
A)呼叫堆疊執行setTimeout(..., 0)
並規劃一個計時器,timeout()
回呼儲存在Web API中:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SLk0AUa5-1611275604642)(/img/bVcMQdg)]
[外鏈圖片轉存失敗,來源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Zr7usYTK-1611275604643)(/img/bVcMQc9)]
#B)呼叫堆疊執行#Promise.resolve (true).then(resolve)
並安排一個promise
解決方案。 resolved()
回呼儲存在Web API中:
[外鏈圖片轉存失敗,來源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JTwSnLYS- 1611275604646)(/img/bVcMQdh)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-k5cRhqzN-1611275604648)(img-k5cRhqzN-1611275604648)(imgdi/bV )]
C)promise 立即被解析,同時計時器也立即執行。這樣,定時器回呼timeout()
進入任務佇列,promise
回呼resolve()
進入作業佇列
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iMfLB2YJ-1611275604649)(/img/bVcMQdS)]
#D)現在是有趣的部分:作業隊列(微任務)優先權高於任務佇列(巨集任務)。事件循環從作業佇列中取出promise回呼resolve()
並將其放入呼叫堆疊中。然後,呼叫堆疊執行promise回呼resolve()
:
[外鏈圖片轉存失敗,來源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nnqfgoo1 -1611275604650)(/img/bVcMQey)]
E)最後,事件循環將計時器回呼timeout()
從任務佇列中出隊到呼叫堆疊中。然後,呼叫堆疊執行計時器回呼timeout()
:
[外鏈圖片轉存失敗,來源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img- Fj54WaI0-1611275604650)(/img/bVcMQeB)]
呼叫堆疊為空,已完成腳本的執行。
為什麼立即解決的 promise 比立即執行計時器處理得更快?
由於事件循環優先權的存在,因此與任務佇列(儲存逾時的setTimeout()
回呼)相比,作業佇列(用於儲存已實作的Promise
回呼)的優先權較高。
原文網址:https://dmitripavlutin.com/javascript-promises-settimeout/
#作者:Milos Protic
譯本網址:https://segmentfault .com/a/1190000038769853
更多電腦程式相關知識,請造訪:程式設計影片! !
以上是深入淺析 Promise 比 setTimeout() 快的原因的詳細內容。更多資訊請關注PHP中文網其他相關文章!