Một nguồn trả lỗi rất sớm, nhưng ứng dụng vẫn muốn chờ kết quả dùng được từ nguồn khác. Promise.any phù hợp khi chỉ cần một tác vụ fulfilled. Trước khi dùng, cần định nghĩa “thành công” ở mức Promise và cách báo lỗi khi không có nguồn nào đáp ứng.
Các ví dụ chạy trong async function hoặc môi trường hỗ trợ top-level await. Toàn bộ dữ liệu nằm trong bộ nhớ, không gọi API và không dùng timer.
1. any không chọn rejection đầu tiên như race
const jobs = [
Promise.reject(new Error('source A failed')),
Promise.resolve('source B data')
];
try {
await Promise.race(jobs);
} catch (error) {
console.log(error.message); // source A failed
}
console.log(await Promise.any(jobs)); // source B data
race lấy kết quả settled đầu tiên, còn any chờ một fulfillment. Xem MDN Promise.race và MDN Promise.any. Ví dụ dùng các Promise đã settled theo thứ tự được đưa vào, không đo tốc độ mạng.
Áp dụng khi các nguồn thực sự có thể thay thế nhau theo contract. Nếu màn hình cần ghép cả hồ sơ lẫn danh sách quyền, lấy một kết quả bất kỳ không đáp ứng yêu cầu đó. Hãy mô tả dữ liệu tối thiểu phải có trước khi chọn phương thức tổng hợp.
2. Khi mọi tác vụ reject, đọc danh sách lỗi
let failA;
let failB;
const a = new Promise((_, reject) => { failA = reject; });
const b = new Promise((_, reject) => { failB = reject; });
const selected = Promise.any([a, b]);
failB(new Error('B unavailable'));
failA(new Error('A unavailable'));
try {
await selected;
} catch (error) {
console.log(error instanceof AggregateError); // true
console.log(error.errors.map(item => item.message).join('|'));
// A unavailable|B unavailable
}
AggregateError gom các lý do từ chối trong errors; xem MDN AggregateError. Trong ví dụ, B lỗi trước nhưng danh sách errors vẫn tương ứng thứ tự đầu vào A rồi B.
Khi ghi nhận lỗi, giữ định danh nguồn cùng vị trí đầu vào. Đừng gán lỗi đầu tiên trong errors cho “dịch vụ lỗi sớm nhất”. Với dữ liệu thực tế, rejection reason có thể không phải Error; đoạn map đọc message ở đây dựa trên chính các Error đã tạo trong ví dụ.
Thông báo giao diện có thể ngắn gọn như “Chưa lấy được dữ liệu từ các nguồn”. Thông tin chẩn đoán chi tiết nên gắn đúng nguồn để người vận hành biết cần kiểm tra dependency nào.
3. Danh sách rỗng đi vào nhánh lỗi
try {
await Promise.any([]);
} catch (error) {
console.log(error instanceof AggregateError); // true
console.log(error.errors.length); // 0
}
Không có ứng viên không tạo ra một giá trị thành công mặc định. Ví dụ cho thấy AggregateError có danh sách lỗi rỗng. Nếu danh sách nguồn đến từ cấu hình, nên phân biệt “không cấu hình nguồn” với “đã thử nguồn nhưng đều thất bại” trong trạng thái ứng dụng.
Cũng cần chính sách cho tác vụ pending kéo dài: một nguồn đã reject và nguồn khác chưa bao giờ settled thì không đủ điều kiện để kết luận mọi nguồn đều lỗi. Thiết kế giới hạn chờ và cleanup ở nơi sở hữu tác vụ.
4. false và dữ liệu chưa hợp lệ vẫn có thể fulfilled
const flag = await Promise.any([
Promise.resolve(false),
Promise.resolve(true)
]);
const payload = await Promise.any([
Promise.resolve({ ok: false, data: null }),
Promise.resolve({ ok: true, data: 'ready' })
]);
console.log(flag); // false
console.log(payload.ok); // false
Ở đây false là một fulfillment bình thường, và object có ok:false cũng không tự biến thành rejection. Nếu sản phẩm yêu cầu payload có schema hoặc điều kiện nhất định, mỗi tác vụ cần kiểm tra contract trước khi tham gia lựa chọn. Đừng kiểm tra sau khi chọn rồi mong any quay lại lấy ứng viên khác.
Việc có kết quả được chọn cũng không tự hủy các công việc còn lại. Cân nhắc tải phát sinh khi gọi nhiều nguồn và trách nhiệm giải phóng tài nguyên; không xem any là cơ chế retry hoặc giới hạn đồng thời.
5. Checklist chọn kết quả dự phòng
- Các ứng viên có cung cấp dữ liệu thay thế tương đương không?
- Điều kiện dữ liệu hợp lệ đã được kiểm tra trong từng tác vụ chưa?
- Mảng rỗng có trạng thái riêng không?
- Lỗi tổng hợp được ghép đúng nguồn theo thứ tự đầu vào không?
- Tác vụ kéo dài và công việc không được chọn được quản lý thế nào?
Tám khối mã Việt–Anh đã chạy bằng Node.js, kèm kiểm tra một rejection trước fulfillment, lý do lỗi không phải Error và tác vụ còn chạy sau khi đã chọn được kết quả. Chưa tích hợp nguồn mạng thật hoặc đo hiệu năng.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.