Generators suspend at yield and resume when a consumer advances them. Resource-owning generators can use finally to release resources when iteration closes.
Step-by-step walkthrough
Step 1: Understand suspension
Calling a generator function creates an iterator without running its body to completion. Next advances execution until yield or completion. Local variables remain associated with that traversal between advances, enabling incremental production.
Step 2: Place release logic in finally
When iteration owns a resource, cleanup should follow that ownership. A try/finally around production can release it when normal iteration ends or the iterator is explicitly closed. Setup should also account for exceptions before a resource is fully acquired.
Step 3: Close early consumption deliberately
Breaking from a for-of loop performs iterator closure. When manually consuming next, the caller may need to invoke return. Merely dropping a still-live iterator is not a timely deterministic cleanup operation.
Worked scenario
Breaking a for-of loop closes the iterator, letting a generator’s finally block run.
function* records() {
try {
yield 'first';
yield 'second';
} finally {
console.log('release resources');
}
}
for (const record of records()) {
console.log(record); // first
break;
}
// release resourcesWalk through the example
Only the first yielded value is consumed. Breaking closes the iterator, which enters its finally block. A real resource-backed generator would release the actual owned resource there. Generator syntax does not move synchronous processing onto another thread; slow work before a yield still occupies the executing thread.
Common mistake
An abandoned iterator can retain resources. Generator syntax does not move CPU work to another thread.
Verify the behavior
Check full traversal, early break and an exception thrown by the consumer. For a manually managed iterator, advance once and call return, verifying cleanup occurs. Also test that acquiring the resource only happens when iteration actually begins if that is the intended contract.
Interview exercise
Stop an iterator managed manually.
Answer and reasoning
Call return when appropriate and place release logic in finally; document who owns closure of the iterator.
Follow-up discussion
Can finally yield more values? The language permits nuanced generator behavior, but cleanup that depends on additional consumption is a fragile resource contract. Prefer direct release. Are generators replayable? Reinvoke the generator function for a fresh iterator rather than reusing an exhausted traversal.
Continue learning
Compare the scenario with the JavaScript interview questions and test your understanding with the JavaScript MCQs. For terminology and implementation details, consult the reference material.