Tôi nghĩ rằng chúng ta không thể thảo luận về vòng lặp sự kiện tách khỏi ngăn xếp, vì vậy:
JS có ba "ngăn xếp":
- ngăn xếp tiêu chuẩn cho tất cả các cuộc gọi đồng bộ (một chức năng gọi một chức năng khác, v.v.)
- hàng đợi microtask (hoặc hàng đợi công việc hoặc ngăn xếp microtask) cho tất cả các hoạt động không đồng bộ với mức độ ưu tiên cao hơn (process.nextTick, Promising, Object.observe, MutingObserver)
- hàng đợi macrotask (hoặc hàng đợi sự kiện, hàng đợi nhiệm vụ, hàng đợi macrotask) cho tất cả các hoạt động không đồng bộ với mức độ ưu tiên thấp hơn (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, kết xuất giao diện người dùng)
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
Và vòng lặp sự kiện hoạt động theo cách này:
- thực hiện mọi thứ từ dưới lên trên từ ngăn xếp và CHỈ khi ngăn xếp trống, kiểm tra xem điều gì đang xảy ra trong hàng đợi ở trên
- kiểm tra ngăn xếp vi mô và thực hiện mọi thứ ở đó (nếu cần) với sự trợ giúp của ngăn xếp, hết nhiệm vụ này đến lần khác cho đến khi hàng đợi microtask trống hoặc không yêu cầu bất kỳ thực thi nào và CHỈ sau đó kiểm tra ngăn xếp macro
- kiểm tra ngăn xếp macro và thực hiện mọi thứ ở đó (nếu cần) với sự trợ giúp của ngăn xếp
Ngăn xếp mico sẽ không được chạm nếu ngăn xếp không trống. Ngăn xếp macro sẽ không được chạm nếu ngăn xếp vi mô không trống HOẶC không yêu cầu thực hiện.
Tóm lại: hàng đợi microtask gần giống như hàng đợi macrotask nhưng các tác vụ đó (process.nextTick, Promising, Object.observe, MutingObserver) có mức độ ưu tiên cao hơn macrot Nhiệm vụ.
Micro giống như macro nhưng với mức độ ưu tiên cao hơn.
Ở đây bạn có mã "cuối cùng" để hiểu mọi thứ.
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();