JS chạy đơn luồng: một call stack thực thi code đồng bộ. Tác vụ bất đồng bộ (timer, network, event) được Web API xử lý bên ngoài rồi đẩy callback vào hàng đợi. Event loop lặp: khi call stack rỗng thì lấy tác vụ tiếp theo ra chạy.
Có hai loại hàng đợi, khác độ ưu tiên:
- Microtask: Promise.then/catch/finally, queueMicrotask, MutationObserver.
- Macrotask (task): setTimeout, setInterval, sự kiện I/O, sự kiện UI (click, message).
Quy tắc: sau mỗi tác vụ, engine rút cạn toàn bộ microtask trước khi lấy macrotask kế tiếp. Vì vậy Promise.then luôn chạy trước setTimeout(…, 0). Việc render trang không phải một macrotask — trình duyệt có thể chèn bước vẽ lại giữa các task, sau khi microtask đã rút cạn.
Minh họa:
console.log('A')
setTimeout(() => console.log('B'), 0)
Promise.resolve().then(() => console.log('C'))
console.log('D')
// → A D C B