for await...of (ES2018) lặp qua async iterable — object implement Symbol.asyncIterator. Dùng để xử lý luồng dữ liệu bất đồng bộ (stream, pagination, real-time).
Cú pháp
for await (const item of asyncIterable) {
// item là giá trị resolved từ Promise
}
Ví dụ 1: Lặp mảng thường (sync) trong async function
<script>
const arr = [1, 2, 3, 4, 5];
async function test() {
for await (const num of arr) {
document.write(num + '<br>');
}
}
test();
</script>
Kết quả
1 2 3 4 5
Ví dụ 2: Custom Async Iterable (Symbol.asyncIterator)
<script>
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 1;
return {
next() {
if (i < 6) {
// Trả về Promise resolve {value, done}
return Promise.resolve({ value: i++, done: false });
}
return Promise.resolve({ done: true });
}
};
}
};
async function consume() {
for await (const num of asyncIterable) {
document.write(num + '<br>');
}
}
consume();
</script>
Kết quả
1 2 3 4 5
Thực tế: Async Generator Function (Dễ hơn)
async function* generateNumbers() {
for (let i = 1; i <= 5; i++) {
await new Promise(r => setTimeout(r, 100)); // Giả lập async delay
yield i;
}
}
async function main() {
for await (const num of generateNumbers()) {
console.log(num); // In 1..5 mỗi 100ms
}
}
main();
Use Case Thực Tế
- Stream processing: ReadableStream, fetch body (
for await (const chunk of response.body)). - Pagination API: Async iterator tự động fetch page tiếp theo.
- Database cursor: Lặp qua kết quả query lớn không load hết vào RAM.
- WebSocket/EventSource: Wrapper async iterator cho message stream.
Lưu ý
- Chỉ dùng trong
async functionhoặc module top-level (ES2022). - Nếu async iterable throw/reject → loop throw, cần
try/catch. break,continue,returnhoạt động bình thường.- Parallel processing: dùng
Promise.allvớimapthay vì for await (sequential).
So sánh
| Loop | Iterable | Item type | Dùng cho |
|---|---|---|---|
for...of | Sync (Symbol.iterator) | Value | Array, Map, Set, String... |
for await...of | Async (Symbol.asyncIterator) | Resolved value | Stream, async generator, paginated API |