Saya pikir kita tidak bisa membahas event loop terpisah dari stack, jadi:
JS memiliki tiga "tumpukan":
- tumpukan standar untuk semua panggilan sinkron (satu fungsi memanggil fungsi lain, dll)
- microtask queue (atau job queue atau microtask stack) untuk semua operasi async dengan prioritas lebih tinggi (process.nextTick, Promises, Object.observe, MutationObserver)
- antrian macrotask (atau antrian acara, antrian tugas, antrian macrotask) untuk semua operasi async dengan prioritas lebih rendah (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, rendering UI)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
Dan loop acara berfungsi seperti ini:
- jalankan semuanya dari bawah ke atas dari tumpukan, dan HANYA ketika tumpukan kosong, periksa apa yang terjadi dalam antrian di atas
- periksa tumpukan mikro dan jalankan semua yang ada (jika diperlukan) dengan bantuan tumpukan, satu tugas mikro demi satu sampai antrian mikrotask kosong atau tidak memerlukan eksekusi apa pun dan HANYA kemudian periksa tumpukan makro
- periksa tumpukan makro dan jalankan semua yang ada (jika perlu) dengan bantuan tumpukan
Mico stack tidak akan disentuh jika stack tidak kosong. Tumpukan makro tidak akan disentuh jika tumpukan mikro tidak kosong ATAU tidak memerlukan eksekusi apa pun.
Singkatnya: antrian mikrotask hampir sama dengan antrian macrotask tetapi tugas-tugas itu (process.nextTick, Promises, Object.observe, MutationObserver) memiliki prioritas lebih tinggi daripada macrotasks.
Mikro seperti makro tetapi dengan prioritas lebih tinggi.
Di sini Anda memiliki kode "pamungkas" untuk memahami segalanya.
console.log('stack [1]');
setTimeout(() => console.log("macro [2]"), 0);
setTimeout(() => console.log("macro [3]"), 1);
const p = Promise.resolve();
for(let i = 0; i < 3; i++) p.then(() => {
setTimeout(() => {
console.log('stack [4]')
setTimeout(() => console.log("macro [5]"), 0);
p.then(() => console.log('micro [6]'));
}, 0);
console.log("stack [7]");
});
console.log("macro [8]");
/* Result:
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4]
micro [6]
stack [4]
micro [6]
stack [4]
micro [6]
macro [5], macro [5], macro [5]
--------------------
but in node in versions < 11 (older versions) you will get something different
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4], stack [4], stack [4]
micro [6], micro [6], micro [6]
macro [5], macro [5], macro [5]
more info: https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3
*/
while (task = todo.shift()) task();