- Published on
解釋 JavaScript 的 Event Loop
Stack Queue
JavaScript 是個單執行緒語言,因此一次只能做一件事,Queue 就是一個等待執行的列表,Stack 就是每次執行的任務,當一個 Stack 執行完畢的時候,就會從 Queue 裡面找下一個 Stack 來執行。
function a() {
console.log('a')
}
function b() {
console.log('b')
}
a()
b()
// a => b
如上例,初始的 Stack 為 a() b() , Queue 是空的,因此結果就是依序執行 a => b。
Macro Micro
除了簡單的依序執行 Stack 這個規則以外,還分為 Macro 及 Micro 兩種排序規則,如果是 Macro,如同一般的 Stack 排序,例如 setTimeout 就是一種 Macro Task。
function a() {
setTimeout(()=>{console.log('aa')},0)
console.log('a')
}
function b() {
console.log('b')
}
a()
b()
// a => b => aa
如上例,初始的 Stack 為 a() b() , 但差別是執行到了 setTimeout 的時候,在 Queue 裡面增加了一個 Stack 執行 console.log('aa'),因此執行的順序為 a => b => aa。
Promise 是 Micro Task 的代表,Micro Task 會排在當前 Stack 的後面,每當 JavaScript 執行完當前 Stack,會優先執行 Micro Task 的 Queue,然後才執行下一個 Stack。
function a() {
setTimeout(()=>{ console.log('aa')},0)
console.log('a')
Promise.resolve().then(function () {
console.log("aaa");
});
}
function b() {
console.log('b')
}
a()
b()
// a => b => aaa => aa
將前例加上一個 Promise,如上所述,先將 aa 與 aaa 移出這個 Stack,所以會先顯示 a => b,aaa 是 Promise,所以 Micro Task 會優先於 Macro Task 執行,所以最後順序就是 a => b => aaa => aa
下例則是加上所有 Macro 與 Micro Task,更複雜的可能心算或畫圖依照規則排好,之後問題就迎刃而解。
function a() {
setTimeout(()=>{ console.log('aa')},0)
console.log('a')
Promise.resolve().then(function () {
console.log("aaa");
});
}
function b() {
setTimeout(()=>{ console.log('bb')},0)
console.log('b')
Promise.resolve().then(function () {
console.log("bbb");
});
}
a()
b()
// 防雷線 --------------------
// a => b => aaa => bbb => aa => bb