1.事件循環的理解
JavaScript是單線程的,意味著它一次只能執行一個任務。而事件循環就是去協調在JavaScript環境中運行的同步任務、異步任務(微任務、宏任務)的執行順序的一種機制。它是 JavaScript 實現單線程非阻塞異步執行的核心。
2.事件循環的執行順序
同步任務——>所有微任務——>一個宏任務——>清空微任務隊列——>一個宏任務.......。每執行完一個宏任務后,再次檢查并執行所有微任務,然后再執行一個宏任務,這就是事件循環。
宏任務:指的是最普通的異步工作,如:setTimeout、setInterval、整段 script、I/O 回調(網絡請求、文件讀寫等)。事件循環每輪只從宏任務隊列里取一個執行。
微任務:包括Promise.then、queueMicrotask、MutationObserver(以及 Node 里的 process.nextTick)。微任務在當前宏任務執行完后立馬執行。
代碼示例:執行順序(A->D->C->B)
console.log('A');setTimeout(() => console.log('B'), 0); // 宏任務Promise.resolve().then(() => console.log('C')); // 微任務console.log('D');
3.擴展
對于添加async和await語法糖來說,async會將異步函數?‘變為’ 同步函數,而await會等待Promise返回的結果后,才會執行await下面的語句,也就是說await把后面的語句注冊為為微任務,而await前面的任務為同步任務。
代碼示例:執行順序(1->2->3->4->5->6->7)
console.log('1. 同步代碼開始');async function foo() {console.log('2. foo 函數體執行(同步)');await bar(); // await 后面那一行是微任務console.log('5. await 后面是微任務,此時 bar 已返回');
}function bar() {console.log('3. bar 執行(同步)');return Promise.resolve(); // 返回一個已決的 Promise
}foo().then(() => {console.log('6. foo 返回的 Promise resolve(微任務)');
});setTimeout(() => {console.log('7. setTimeout 回調(宏任務)');
}, 0);console.log('4. 同步代碼結束');