EventLoop瀏覽器/宏任務/微任務概念及示例
- 一、概念
- 1.什么是EventLoop:
- 2.什么是宏任務/微任務:
- 二、執行順序
- 三、示例決議
- 以上便是我對這個知識點的梳理總結,比較粗淺,如果有錯誤的地方請指正、如果對您有幫助請點個贊或收個藏給作者一點鼓勵吧! 謝謝!
最近看了很多關于瀏覽器EventLoop的文章,學習了很多,這里將這些進行一個簡單的總結:
一、概念
1.什么是EventLoop:
Event Loop是一個程式結構,用于等待和發送訊息和事件,(a programming construct that waits for
and dispatches events or messages in a program.)簡單來說就是計算機系統的一種運行機制
2.什么是宏任務/微任務:
在ES6 規范中是這樣定義的,microtask 稱為 jobs,macrotask 稱為 task
宏任務是由宿主發起的,而微任務由JavaScript自身發起,
1) 宏任務有哪些:
- script的全部代碼
- setTimeout
- setInterval
- setImmediate
- I/O
- UI-Render
- postMessage
- MessageChannel
(對于普通的使用我們大部分關注和注意的應該是Script全部代碼、setTimeout、setInterval)
2) 微任務有哪些:
- Process.nextTick(node.js獨有)
- Promise
- MutaionObserver
- 以Promise為基礎開發的其它技術(async/await等)
二、執行順序
- 首先我們都知道JS是一個單執行緒的運行機制,在同步操作的情況下我們的代碼是一個從上往下的運行程序.上面寫到了Script的代碼是宏任務,那么我們代碼的執行一開始可視作一個宏任務的執行,而每一個宏任務里都定義了一個微任務的佇列,每當當前宏任務執行完成之后便會去檢查微任務佇列里是否有微任務,如果有,就執行,直到微任務佇列執行完成,這時便回到宏任務佇列去執行下一個宏任務,如此回圈便是瀏覽器的EventLoop
- 宏任務佇列執行當前宏任務 --> 當前宏任務執行完成查找當前宏任務中微任務佇列 --> 微任務佇列執行完成(微任務佇列為空) --> 在宏任務佇列執行下一個宏任務
- 以上便是簡單理解瀏覽器的EventLoop
三、示例決議
A. 首先看一個基礎示例
console.log('script-start')
setTimeout(() => {
console.log('settimeout');
});
console.log('script-end');
//列印順序為 script-start
// script-end
// settimeout
分析: 首先進入代碼執行,外層同步代碼為第一個宏任務執行,從上往下
- 執行 console.log(‘script-start’) 列印第一個log script-start
- 遇到定時器setTimeout,屬于宏任務,將定時器里的任務放到宏任務佇列
- 繼續往下執行 console.log(‘script-end’) 列印第二個log script-end
- 此時宏任務執行完成,查找微任務佇列為空,則回到宏任務佇列查找下一個宏任務,為剛剛碰到的定時器setTimeout
- 執行宏任務setTimeout console.log(‘settimeout’) 列印第三個log settimeout
B. 增加微任務promise的示例
console.log('script-start')
setTimeout(() => {
console.log('settimeout');
});
new Promise((resolve, reject) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise1-then');
});
console.log('script-end');
//列印順序為 script-start
// promise1
// script-end
// promise1-then
// settimeout
分析: 首先進入代碼執行,外層同步代碼為第一個宏任務執行,從上往下
- 執行 console.log(‘script-start’) 列印第一個log script-start
- 遇到定時器setTimeout,屬于宏任務,將定時器里的任務放到宏任務佇列
- 遇到Promise,首先都知道Promise創建便執行,于是執行console.log(‘promise1’) 列印第二個log promise1
- 由于Promise的回呼是微任務,所以將Promise的回呼也就是then中的代碼放到微任務佇列
- 繼續往下執行 console.log(‘script-end’) 列印第三個log script-end
- 此時宏任務執行完成,查找微任務佇列,發現剛剛放進微任務的promise的回呼
- 執行promise.then中的代碼 執行console.log(‘promise1-then’) 列印第四個log promise1-then
- 再查找微任務佇列,為空了,則回到宏任務佇列查找下一個宏任務,為剛剛碰到的定時器setTimeout
- 執行宏任務setTimeout console.log(‘settimeout’) 列印第五個log settimeout
C. 增加async/await的示例
console.log('script-start')
async function a() {
console.log('a-start');
await b();
console.log('a-end');
}
async function b() {
console.log('b');
}
a()
setTimeout(() => {
console.log('settimeout');
});
new Promise((resolve, reject) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise1-then');
});
console.log('script-end');
//列印順序為 script-start
// a-start
// b
// promise1
// script-end
// a-end
// promise1-then
// settimeout
分析: 首先進入代碼執行,外層同步代碼為第一個宏任務執行,從上往下
- 執行 console.log(‘script-start’) 列印第一個log script-start
- 碰到async a 以及 async b的函式宣告,但是沒有執行,所以繼續往下
- 遇到a(),執行async a進入a函式執行,遇到console.log(‘a-start’) 列印第二個log a-start
- 碰到await b() 先進入b函式執行, 遇到console.log(‘b’) 列印第三個log b
- b()執行完成回到a()函式中,這時候await下面還有陳述句,怎么辦呢? 答案是將下面的陳述句作為一個微任務,放進微任務佇列里
- 然后跳出a()函式 繼續往下執行
- 遇到定時器setTimeout,屬于宏任務,將定時器里的任務放到宏任務佇列
- 遇到Promise,執行console.log(‘promise1’) 列印第四個log promise1
- 將Promise的回呼也就是then中的代碼放到微任務佇列
- 繼續往下執行 console.log(‘script-end’) 列印第五個log script-end
- 此時宏任務執行完成,查找微任務佇列,此時微任務佇列里第一個微任務便是我們放進去的async里await下面的代碼,也就是 console.log(‘a-end’) 執行列印第六個log a-end
- 再繼續執行微任務,也就是執行promise.then中的代碼 執行console.log(‘promise1-then’) 列印第七個log promise1-then
- 再查找微任務佇列,為空了,則回到宏任務佇列查找下一個宏任務,為剛剛碰到的定時器setTimeout
- 執行宏任務setTimeout console.log(‘settimeout’) 列印第八個log settimeout
重點:
- 可能在這里大家就比較疑惑了,async/await的執行到底是怎么樣的?
- 這里簡單的解釋一下,我理解的async/await實際是Promise的一個語法糖,或者說是以Promise為基礎的新技術吧,async函式中的await實際類似于Promise中的.then,首先因為代碼是從右往左執行的,所以當執行到await這一行的時候,應該先從右邊執行,執行完成了之后,碰到await,而await又相當于是一個Promise的.then效果,所以將接下來要執行的下面的代碼作為一個微任務放到了微任務佇列中
也就是說async/await函式中:
- 從上往下執行 --> 碰到await陳述句先執行右側代碼 --> 右側代碼執行完成之后將await左側代碼及下面代碼放進微任務佇列
–> 跳出async函式執行外層同步代碼
以上便是我對這個知識點的梳理總結,比較粗淺,如果有錯誤的地方請指正、如果對您有幫助請點個贊或收個藏給作者一點鼓勵吧! 謝謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/264159.html
標籤:其他
