Cả hai đều là hàng đợi công việc bất đồng bộ, nhưng microtask được ưu tiên tuyệt đối.
| Microtask | Macrotask | |
|---|---|---|
| Nguồn | .then/.catch/.finally, await, queueMicrotask, MutationObserver | setTimeout, setInterval, sự kiện I/O, sự kiện DOM |
| Khi nào chạy | hết sạch queue sau mỗi macrotask | một cái mỗi vòng lặp |
javascript
console.log('1 sync')
setTimeout(() => console.log('5 macro'), 0)
Promise.resolve()
.then(() => console.log('3 micro'))
.then(() => console.log('4 micro'))
queueMicrotask(() => console.log('3b micro'))
console.log('2 sync')
// 1 sync → 2 sync → 3 micro → 3b micro → 4 micro → 5 macroVòng lặp thực tế của browser:
chạy hết code đồng bộ
→ xử lý HẾT microtask queue
→ browser có thể render (style, layout, paint)
→ lấy MỘT macrotask
→ quay lại xử lý microtaskĐiểm hay bị nói sai: render không phải macrotask. Nó là một bước riêng của browser, chen giữa các macrotask.
Hệ quả nguy hiểm: microtask sinh ra microtask mới sẽ chặn render vĩnh viễn, vì queue không bao giờ rỗng:
javascript
function loop() { Promise.resolve().then(loop) }
loop() // trang treo, dù không có vòng lặp đồng bộ nàoMuốn nhường lượt cho browser vẽ thì phải dùng macrotask (setTimeout) hoặc scheduler.yield().