Tasks, microtasks, Promise chains và cancellation
Async không tự song song CPU; host event loop chọn task, chạy JS đến completion rồi drain microtasks trước rendering opportunities.
1. Event loop và queues
Host có task sources/queues; sau task, microtask checkpoint chạy Promise reactions và queueMicrotask trước cơ hội render/next task. Browser/Node có host-specific phases, nên test observable ordering thay vì dùng một sơ đồ universal.
task -> run JS to completion -> drain microtasks -> render opportunity -> next task
2. Promise semantics
Promise là eventual settlement; then trả promise mới và adopts returned thenable. Error propagate theo chain; thiếu return tạo floating work và thiếu catch có thể thành unhandled rejection. Promise không làm CPU-bound code chạy song song.
| Combinator | Behavior | Use |
|---|---|---|
all | Fail-fast khi một reject | All results required, side effects đã có cleanup |
allSettled | Thu mọi outcome | Batch/report từng item |
race | First settled | Timeout wrapper nhưng phải abort loser |
any | First fulfilled | Fallback replicas; AggregateError nếu tất cả fail |
3. Concurrency, stale response và backpressure
Giới hạn concurrency theo resource/dependency thay vì Promise.all hàng nghìn item. Guard stale responses bằng request identity/version khi user đổi query nhanh; queue/buffer phải bounded để producer không làm cạn memory.
4. Cancellation và timeout
Promise không cancel intrinsic. AbortController/AbortSignal truyền cancellation tới fetch/API hỗ trợ; cleanup listener/timer và distinguish abort khỏi genuine error. Timeout nên abort underlying work, không chỉ race một promise rồi để socket/timer tiếp tục.
const controller = new AbortController();
const timer = setTimeout(() => controller.abort("deadline"), 1000);
try { await fetch(url, {signal: controller.signal}); }
finally { clearTimeout(timer); }