都知道javascript是單執行緒,那麼問題來了,既然是單執行緒順序執行,那怎麼做到非同步的呢?
我們理解的單執行緒應該是這樣的,排著一個個來,是同步執行。
現實中js是這樣的
setTimeout(function() {
console.log(1);
});
new Promise(function(resolve, reject) {
console.log(2)
resolve(3)
}).then(function(val) {
console.log(val);
})
console.log(4)
//執行結果為 2、4、3、1
複製程式碼
結果告訴我們,js是單執行緒沒錯,不過不是逐行同步執行。
那我們就來解析一下既然有非同步,那順序是怎樣的?這些執行順序規則就是理解eventLoop的要點,繼續往下。
上圖為我錄製的chrome控制程式碼臺執行順序,雖然能看出執行順序但我們還是懵逼的,我們不知道規則,不懂就要問。
搜尋了很多官方、個人部落格得到了一堆詞:js引擎、主執行緒、事件表、事件佇列、巨集任務、微任務,徹底懵逼。。。
不急不急一個個來,我們進入刨根問底狀態
js引擎
總結一句話就是解析優化程式碼 **制定執行規則 具體規則往下看
主執行緒
總結一句話執行js引擎優化並排列順序後的程式碼
事件表(event table)
執行程式碼過程中,非同步的回撥,例如(setTimeout,ajax回撥)註冊回撥事件到event table
事件佇列
當事件回撥結束,事件表(event table)會將事件移入到事件佇列(event queue)
#巨集任務和微任務
巨集任務包含的事件
事件 | 瀏覽器 | node |
---|---|---|
I/O | ✅ | ✅ |
setTimeout | ✅ | ✅ |
setInterval | ✅ | ✅ |
setImmediate | ❌ | ✅ |
requestAnimationFrame | ✅ | ❌ |
微任務包含的事件
事件 | 瀏覽器 | node |
---|---|---|
I/O | ✅ | ✅ |
process.nextTick | ❌ | ✅ |
MutationObserver | ✅ | ❌ |
Promise.then catch finally | ✅ | ✅ |
很多部落格是這樣說的:
瀏覽器會不斷從task佇列中按順序取task執行,每執行完一個task都會檢查microtask佇列是否為空(執行完一個task的具體標誌是函式執行棧為空),如果不為空則會一次性執行完所有microtask。然後再進入下一個迴圈去task佇列中取下一個task執行
說實話不是太理解,那麼我就以自己的方式去學習和理解
為了更好的理解我們再看程式碼
console.log(`1`);
setTimeout(function() {
console.log(`2`);
new Promise(function(resolve) {
console.log(`3`);
resolve();
}).then(function() {
console.log(`4`)
})
})
new Promise(function(resolve) {
console.log(`5`);
resolve();
}).then(function() {
console.log(`6`)
})
setTimeout(function() {
console.log(`7`);
new Promise(function(resolve) {
console.log(`8`);
resolve();
}).then(function() {
console.log(`9`)
})
})
//執行結果:1、5、6、2、3、4、7、8、9
複製程式碼
有圖為證我沒騙你
再來個動圖我們具體看看瀏覽器的執行順序
首先js引擎,區分是直接執行(同步程式碼),再執行非同步程式碼,如果是非同步再區分是巨集任務還是微任務,分別放入兩個任務佇列,然後開始執行,每執行完一個巨集任務,掃一遍微任務佇列並全部執行,此時形成一次eventLoop迴圈。以此規則不停的執行下去就是我們所聽到的事件迴圈。
我再補充一點,可以理解js引擎一開始把整個script當做一個巨集任務,這樣裡邊的就更容易理解了,開始就執行script巨集任務,解析到巨集任務裡邊又包含同步程式碼和非同步程式碼(巨集任務和微任務)依次執行順序形成eventLoop。
歡迎吐槽點贊評論!
文章參考學習:
www.jianshu.com/p/12b9f73c5…
juejin.im/post/59e85e…
segmentfault.com/a/119000001…