事件迴圈、巨集任務、微任務
阿新 • • 發佈:2021-07-26
*巨集任務*:在js中,在主執行緒上執行的任務叫巨集任務,常見的有:
- 1渲染事件
- 使用者互動事件
- js指令碼
- 網路請求、檔案讀寫完成事件
- 延遲事件(定時器)
普通任務佇列、延遲佇列中的任務都屬於巨集任務。
為了讓這些事件有條不紊的進行,js引擎需要對執行的順序做一定的安排,v8其實採用是一種佇列的方式來儲存這些任務,即先進來的先執行。
*微任務*:對於每個巨集任務而言,其內部都有一個微任務佇列,那為什麼要引入微任務?微任務在什麼時候執行?
引入微任務的初衷是為了解決非同步回撥問題,如果把非同步回撥放在巨集任務,會造成卡頓。為了解決這一問題,v8引入微任務,在每一個巨集任務中定義一個微任務佇列,當該巨集任務執行完成,會檢查其中的微任務佇列,如果為空則執行下一個巨集任務,如果不為空,則依次執行微任務,執行完成採取執行下一個巨集任務。常見的微任務有:
- MutationObserver
- Promise.then(或.reject)以及以Promise為基礎開發的其他技術(比如fetch API)
- v8垃圾回收機制
- nextTick
事件迴圈--js執行機制(eventLoop)
例子:
console.log('start');
setTimeout(() => { console.log('timeout');});
Promise.resolve().then(() => { console.log('resolve');});
console.log('end');
分析一下:
1)剛開始整個指令碼作為一個巨集任務來執行,因此先列印start和end
2)setTimeout 作為一個巨集任務放入巨集任務佇列
3)Promise.then作為一個為微任務放入到微任務佇列
4)當本次巨集任務執行完,檢查微任務佇列,發現一個Promise.then, 執行5)接下來進入到下一個巨集任務——setTimeout, 執行
start
end
resolve
timeout
1)一開始整段指令碼作為第一個巨集任務執行
2)執行過程中同步程式碼直接執行,巨集任務進入巨集任務佇列,微任務進入微任務佇列
3)當前巨集任務執行完出隊,檢查微任務佇列,如果有則依次執行,直到微任務佇列為空
4)執行瀏覽器 UI 執行緒的渲染工作
5)檢查是否有Web worker任務,有則執行
6)執行隊首新的巨集任務,回到2,依此迴圈,直到巨集任務和微任務佇列都為空
// 練習
Promise.resolve().then(()=>{ console.log('Promise1') setTimeout(()=>{ console.log('setTimeout2') },0)});
setTimeout(()=>{ console.log('setTimeout1') Promise.resolve().then(()=>{ console.log('Promise2') })},0);
console.log('start');
// start// Promise1// setTimeout1// Promise2// setTimeout2