- Home
- /
- Tutorials
- /
- JavaScript Tutorial
- /
- JavaScript Async Iteration
JavaScript Generators & Iterators
JavaScript Async Iteration
for await ofloops over values that arrive one at a time, each behind a promise.
A normal generator yields values instantly.
An async generator can await before yielding each one.
Example
Example
javascript
async function* countSlowly(max) {
for (let i = 1; i <= max; i++) {
await Promise.resolve();
yield i;
}
}
async function run() {
const values = [];
for await (const n of countSlowly(3)) {
values.push(n);
}
return values.join(",");
}
run().then(function (result) {
console.log(result);
});The output is 1,2,3, each one awaited before it arrived.
async function* and for await
async function* declares an async generator.
Inside it, both await and yield can be used.
for await (const x of source) consumes it, awaiting each value.
Syntax
Syntax
javascript
async function* source() {
yield await getValue();
}
for await (const value of source()) {
}for await only works inside an async function.
Each Value Is Awaited
The loop pauses for every value, not just once at the start.
Example
Example
javascript
async function* fetchEach(items) {
for (const item of items) {
const value = await Promise.resolve(item.toUpperCase());
yield value;
}
}
async function run() {
const results = [];
for await (const value of fetchEach(["a", "b"])) {
results.push(value);
}
return results.join(",");
}
run().then(function (result) {
console.log(result);
});The output is A,B.
Handling a Rejected Value
An error partway through can be caught around the whole loop.
Example
Example
javascript
async function* source() {
yield 1;
await Promise.reject(new Error("stream failed"));
yield 2;
}
async function run() {
const values = [];
try {
for await (const n of source()) {
values.push(n);
}
} catch (error) {
values.push("caught: " + error.message);
}
return values.join(",");
}
run().then(function (result) {
console.log(result);
});The output is 1,caught: stream failed.
for await Also Accepts Plain Values
An async generator can mix immediate and awaited yields freely.
Example
Example
javascript
async function* mixed() {
yield 1;
yield await Promise.resolve(2);
yield 3;
}
async function run() {
const values = [];
for await (const n of mixed()) {
values.push(n);
}
return values.join(",");
}
run().then(function (result) {
console.log(result);
});The output is 1,2,3.
A Normal Generator Also Works
for await can consume a plain synchronous iterable too.
It simply awaits each value, which does nothing extra if it is not a promise.
Example
Example
javascript
function* plain() {
yield 1;
yield 2;
}
async function run() {
const values = [];
for await (const n of plain()) {
values.push(n);
}
return values.join(",");
}
run().then(function (result) {
console.log(result);
});The output is 1,2, exactly as a plain for of would give.
Where This Is Used
Reading a network response in chunks is the classic real example.
Each chunk arrives over time, which is exactly what this loop is built for.
Example
Example
javascript
async function* chunks() {
yield "first chunk";
yield "second chunk";
}
async function run() {
const parts = [];
for await (const chunk of chunks()) {
parts.push(chunk);
}
return parts.join(" + ");
}
run().then(function (result) {
console.log(result);
});Streaming APIs in the browser expose data in exactly this shape.
Complete Example
Complete Example
html
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Async Iteration</title>
</head>
<body>
<h1>Async Iteration</h1>
<p id="out">Loading...</p>
<script>
async function* fetchNames() {
const names = ["Ada", "Grace", "Alan"];
for (const name of names) {
await new Promise(function (resolve) { setTimeout(resolve, 10); });
yield name;
}
}
async function run() {
const found = [];
for await (const name of fetchNames()) {
found.push(name);
}
document.getElementById("out").textContent = found.join(", ");
}
run();
</script>
</body>
</html>Try It Yourself
Run the above example in the Try It Editor.
Try reporting progress:
Update #out inside the loop instead of only at the end.
Important Points
async function*declares an async generator.- Both
awaitandyieldcan be used inside it. for awaitconsumes it, awaiting each value in turn.- An error can be caught around the whole loop with
try catch. for awaitalso works on plain synchronous iterables.
Conclusion
Async iteration extends the generator pattern to values that arrive over time.
It is the natural fit for streaming data, one piece at a time.
Everything from ordinary generators still applies; only the timing changes.
