Rejection không có handler sẽ được báo cáo khi microtask queue đã rút cạn mà promise vẫn chưa có catch:
- Trình duyệt: phát sự kiện
unhandledrejectiontrênwindow, log đỏ ở console; trang vẫn chạy. Có thểevent.preventDefault()để chặn log và tự gửi lên Sentry. - Node.js: từ v15 mặc định
--unhandled-rejections=throw→ kết thúc process. Đây là lý do fire-and-forget trên server rất rủi ro.
window.addEventListener('unhandledrejection', (event) => {
report(event.reason)
event.preventDefault()
})Vì sao Promise.all hay dính: nó fail-fast — reject ngay khi promise đầu tiên hỏng, nhưng các promise còn lại vẫn chạy tiếp.
Nếu promise thứ hai cũng reject thì lúc đó Promise.all đã settle rồi, không còn ai nhận lỗi đó → unhandled rejection thứ hai.
await Promise.all([failFast(), alsoFailsLater()]) // lỗi thứ hai không ai bắtCách xử lý: dùng Promise.allSettled khi cần biết mọi kết quả, hoặc gắn .catch() cho từng promise trước khi đưa vào all, và truyền AbortSignal chung để phần việc còn lại dừng thật.
Một bẫy liên quan: gắn catch muộn (sau một await khác) có thể vẫn kịp vì handler được gắn trong cùng vòng microtask — nhưng nếu trễ hơn một task thì cảnh báo đã bắn. Đừng dựa vào timing này.