async function* dataStream() {
for (let i = 1; i <= 5; i++) {
await new Promise(r => setTimeout(r, 100));
yield i;
}
}
async function consume() {
const gen = dataStream();
console.log((await gen.next()).value); // 1
console.log((await gen.next()).value); // 2
// Simulate error from consumer side:
await gen.throw(new Error('Consumer cancelled'));
// Generator has no try/catch β error propagates to consume()
// No cleanup happens in the generator
}async function* dataStream() {
try {
for (let i = 1; i <= 5; i++) {
await new Promise(r => setTimeout(r, 100));
yield i;
}
} catch (err) {
console.log('Generator caught:', err.message);
// Handle gracefully, or rethrow
} finally {
console.log('Generator cleaning up resources');
// Always runs: close DB connections, unsubscribe, etc.
}
}
async function consume() {
const gen = dataStream();
console.log((await gen.next()).value); // 1
console.log((await gen.next()).value); // 2
// throw() sends error into generator at the current yield
await gen.throw(new Error('Consumer cancelled'));
}Bug: When gen.throw() is called, the error appears inside the generator at the yield point. Without try/finally in the generator, no cleanup runs.
Explanation: gen.throw(err) sends an error into the generator at its current suspension point. try/catch inside the generator catches it. try/finally ensures cleanup whether the error is caught or not.
Key Insight: Generators can receive errors via .throw(). Always wrap async generator bodies in try/finally to ensure cleanup when errors are thrown in from outside.