Step 1 of 5 · Reading · ~3 min
Learn
Iteration and Generators
Iterators and Generators
In JavaScript Intermediate you wrote function*, used yield, and built an infinite sequence. This lesson is about what the generator object does underneath: values travelling in both directions, delegating to another generator, and running cleanup code when a consumer stops early. By the end you can write a lazy pipeline stage that shuts its source down correctly.
A generator is a paused function you drive by hand
Calling a generator function runs none of its body. It returns a generator object with three methods: next(value), return(value) and throw(error). Each next() runs the body up to the following yield and reports { value, done }.
for...of and spread ignore the return value (the done: true result is not an element), so [...countdown()] is [3, 2].
Values go in as well as out
yield is an expression. Whatever you pass to the next next(arg) becomes the result of the yield that is paused. The argument of the very first next() has no paused yield to land on, so it is discarded.
yield* delegates to another iterable
yield* inner yields every value of inner, forwards next(arg), throw and return into it, and evaluates to the value inner returned:
Cleanup: return() and finally
When a consumer stops early, it calls return() on the generator. That resumes the paused yield as if it were a return statement, so finally blocks run. for...of does this for you on break, on return, and when the loop body throws; array destructuring does it after taking the elements it needs.
Two details decide real bugs. A generator that has not started has nothing to clean up, so return() on it runs no finally. And a generator that finished normally has already run its finally; asking again does nothing.
Async generators
async function* produces values that may need await; consume them with for await. Each next() returns a Promise. CommonJS has no top-level await, so wrap the loop in an async function.
Common mistakes
- Pulling one value too many. A stage that checks its limit only after asking the source for another value makes the source do work (and print, and close) that never should have happened.
- Looping over a generator twice. It is single-use: the second
for...ofseesdone: trueimmediately and runs zero times. - Driving the protocol by hand with
next()and never callingreturn()when you stop. The source'sfinallynever runs and its resource stays open.
Your exercise
You will write the two stages of a lazy pipeline, concat and take, and the starter's sources print when they are shut down. The closed lines in the output are the test of your take.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…