Rejection không có handler sẽ được báo cáo khi microtask queue đã chạy hết 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.
js
window.addEventListener('unhandledrejection', (event) => {
report(event.reason)
event.preventDefault()
})Promise.all có dính không: thật ra không — Promise.all gắn handler vào mọi promise nó nhận, nên lỗi thứ hai không thành unhandled rejection.
- Nó fail-fast: reject ngay khi promise đầu tiên hỏng, các promise còn lại vẫn chạy tiếp, và lỗi của chúng bị nuốt mất — không ai được báo.
- Chỗ dễ sinh unhandled rejection thật là tạo nhiều promise trước rồi
awaittừng cái:const a = fetchA(); const b = fetchB(); await a; await b—breject trong lúc đang chờathì chưa có ai gắn handler chob.
js
await Promise.all([failFast(), alsoFailsLater()]) // lỗi thứ hai bị nuốt im lặng — không unhandled, nhưng cũng không ai thấyCá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.