Đã viết await trong callback nhưng filter vẫn giữ cả phần tử không đạt điều kiện. Vấn đề nằm ở giá trị mà callback trả ngay cho filter. Cần tách bước chờ kết quả kiểm tra khỏi bước chọn phần tử, đồng thời xác định cách xử lý lỗi và mức đồng thời.
Các khối mã chạy trong async function hoặc môi trường hỗ trợ top-level await. Chúng dùng dữ liệu trong bộ nhớ, không gọi mạng và không cần timer.
1. Callback async trả Promise thay vì boolean trực tiếp
const values = [1, 2, 3];
const selected = values.filter(async value => {
await Promise.resolve();
return value % 2 === 0;
});
console.log(JSON.stringify(selected)); // [1,2,3]
console.log(Array.isArray(selected)); // true
filter dùng truthiness của kết quả callback; một Promise là object truthy. Hàm async luôn trả Promise, kể cả khi mã nguồn viết return false. Xem MDN filter và MDN async function.
Viết await values.filter(...) bên ngoài cũng không sửa được điều kiện chọn: filter đã trả mảng trước đó. Đừng dùng độ dài kết quả trong ví dụ như bằng chứng cả ba phần tử đã vượt qua kiểm tra.
2. Chờ quyết định rồi lọc bằng callback đồng bộ
async function filterConcurrent(items, predicate) {
const snapshot = items.slice();
const decisions = await Promise.all(snapshot.map(item => predicate(item)));
return snapshot.filter((_, index) => decisions[index] === true);
}
const selected = await filterConcurrent([1, 2, 3, 4], async value => {
await Promise.resolve();
return value % 2 === 0;
});
console.log(JSON.stringify(selected)); // [2,4]
Helper minh họa nhận mảng đặc đã kiểm tra đầu vào; predicate phải trả boolean hoặc Promise của boolean. Nó chỉ giữ quyết định bằng true, không nhận các mã số hay chuỗi thay cho quyết định. Promise.all giữ thứ tự kết quả theo thứ tự đầu vào, dù tác vụ kết thúc khác thứ tự; xem MDN Promise.all.
snapshot cố định danh sách và vị trí cho lần chạy này. Đây là bản sao nông: nếu phần tử là object, nội dung của nó vẫn có thể bị nơi khác sửa trong lúc chờ. Nếu điều kiện cần một phiên bản dữ liệu bất biến, hãy xác định dữ liệu hoặc version dùng để kiểm tra trước khi bắt đầu.
map gọi các predicate mà không đợi từng kết quả. Đừng áp helper này trực tiếp cho hàng nghìn request nếu dịch vụ có giới hạn; hãy dùng batch hoặc cơ chế giới hạn đồng thời theo tải thực tế. Promise.all không tự tạo giới hạn đó.
3. Lọc tuần tự khi mỗi lần kiểm tra cần được chờ riêng
async function filterSequential(items, predicate) {
const snapshot = items.slice();
const selected = [];
for (const item of snapshot) {
if ((await predicate(item)) === true) selected.push(item);
}
return selected;
}
const events = [];
const selected = await filterSequential([1, 2, 3], async value => {
events.push('check:' + value);
return value % 2 === 0;
});
console.log(JSON.stringify(selected)); // [2]
console.log(events.join('|')); // check:1|check:2|check:3
Ở phiên bản này, vòng lặp đợi xong lần kiểm tra hiện tại rồi mới gọi lần tiếp theo. Nó dễ diễn giải khi dependency yêu cầu tuần tự, nhưng có thể làm tăng tổng thời gian chờ với tác vụ độc lập. Chọn theo contract và đo tải thay vì mặc định rằng càng nhiều Promise càng nhanh.
4. Lỗi kiểm tra không đồng nghĩa phần tử không đạt
const values = [1, 2, 3];
try {
const decisions = await Promise.all(values.map(async value => {
if (value === 2) throw new Error('check unavailable');
return true;
}));
console.log(JSON.stringify(decisions));
} catch (error) {
console.log(error.message); // check unavailable
}
Ví dụ chọn báo lỗi cả lần lọc thay vì biến một dịch vụ không phản hồi thành quyết định false. Nếu sản phẩm cho phép kết quả một phần, hãy biểu diễn trạng thái lỗi riêng và quyết định cách hiển thị. Với kiểm tra quyền, giao diện lọc chỉ phục vụ trải nghiệm; server vẫn phải xác thực quyền cho thao tác thật.
Trong bản tuần tự, lỗi làm những lần kiểm tra sau chưa được gọi. Trong bản đồng thời, các tác vụ đã bắt đầu có thể vẫn tiếp tục. Việc nhận rejection không tự hoàn tác tác dụng phụ.
5. Bộ test cần có cả false và thứ tự hoàn tất đảo ngược
- Predicate trả false phải loại đúng phần tử.
- Giữ thứ tự đầu vào dù kết quả kiểm tra đến khác thứ tự.
- Định nghĩa đầu ra của predicate là boolean rõ ràng.
- Thử mảng rỗng và lỗi từ một predicate.
- Kiểm tra giới hạn đồng thời trước khi gọi dịch vụ thật.
Tám khối mã Việt–Anh đã chạy bằng Node.js, cùng kiểm tra hoàn tất đảo thứ tự, lỗi, mảng rỗng và việc bản tuần tự dừng gọi sau lỗi. Chưa tích hợp API hoặc đo hiệu năng mạng.




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