0

JavaScript: chạy nhiều promise cùng lúc bằng Promise.allSettled — một lỗi không làm hỏng cả lô

Khi cần gọi nhiều API độc lập cùng lúc — ví dụ lấy thông tin người dùng, danh sách bài viết và số liệu thống kê cho một trang dashboard — Promise.allSettled() là lựa chọn đúng. Nó chờ mọi promise hoàn thành rồi trả về kết quả của từng cái, nên một API lỗi cũng không làm mất dữ liệu của các API còn lại. Chỉ dùng nó khi các tác vụ độc lập với nhau và bạn chấp nhận kết quả từng phần; nếu mọi tác vụ bắt buộc phải thành công thì Promise.all() vẫn phù hợp hơn.

Vấn đề

Giả sử trang dashboard gọi ba API cùng lúc bằng Promise.all():

const [user, posts, stats] = await Promise.all([
  fetch("/api/user").then((r) => r.json()),
  fetch("/api/posts").then((r) => r.json()),
  fetch("/api/stats").then((r) => r.json()),
]);

Chỉ cần API thống kê trả về lỗi 500, toàn bộ Promise.all() bị reject ngay lập tức. Hai API còn lại dù đã trả dữ liệu đúng vẫn bị bỏ đi, trang dashboard trắng trơn và người dùng phải tải lại toàn bộ. Khó chịu hơn khi các API không liên quan gì đến nhau: dữ liệu người dùng và bài viết hoàn toàn có thể hiển thị trước, chỉ riêng khối thống kê cần báo lỗi.

Giải pháp

Promise.allSettled() chờ tất cả promise kết thúc — thành công hay thất bại — rồi trả về một mảng kết quả giữ đúng thứ tự đầu vào. Mỗi phần tử có status là fulfilled kèm value, hoặc rejected kèm reason, nên bạn lọc ra phần thành công để hiển thị và xử lý riêng phần lỗi:

const results = await Promise.allSettled([
  fetch("/api/user").then((r) => r.json()),
  fetch("/api/posts").then((r) => r.json()),
  fetch("/api/stats").then((r) => r.json()),
]);

const [user, posts, stats] = results.map((r) =>
  r.status === "fulfilled" ? r.value : null
);

if (stats === null) {
  console.warn("Không tải được thống kê:", results[2].reason);
}

Với cách này, dashboard vẫn hiển thị thông tin người dùng và bài viết, chỉ khối thống kê hiện thông báo lỗi. Bạn cũng có thể gom các lỗi lại để ghi log, hoặc chỉ gọi lại những API bị lỗi thay vì gọi lại toàn bộ.

Áp dụng vào dự án

Dùng Promise.allSettled() ở bất cứ đâu bạn gọi nhiều tác vụ độc lập và muốn giữ lại kết quả từng phần: dashboard gọi nhiều API, job import xử lý một lô file, màn hình trạng thái kiểm tra nhiều dịch vụ cùng lúc, hay tính năng gửi email cho nhiều người nhận mà một địa chỉ sai không được chặn cả lô. Quy tắc cần nhớ: tác vụ độc lập → allSettled, tác vụ bắt buộc phải thành công hết → Promise.all.

Câu hỏi thường gặp

Promise.allSettled() khác Promise.all() thế nào? Promise.all() dừng ngay khi một promise reject và bỏ hết kết quả, còn Promise.allSettled() chờ mọi thứ xong và trả về trạng thái từng tác vụ, nên bạn luôn giữ được dữ liệu của các tác vụ thành công.

Khi nào vẫn nên dùng Promise.all()? Khi các bước phụ thuộc nhau hoặc tất cả đều phải thành công — ví dụ tạo đơn hàng trước khi trừ kho. Lúc đó một bước lỗi phải dừng toàn bộ luồng, và hành vi fail-fast của Promise.all() mới là lựa chọn đúng.


Đọc bản đầy đủ bằng tiếng Anh tại: https://linhfish.dev/en/2026/11/08/javascript-run-multiple-promises-at-once-with-promise-allsettled-one-failure-wont-ruin-the-batch/


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí