Skip to content
Lesson 1 of 8

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 }.

javascript

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.

javascript

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:

javascript

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.

javascript

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.

javascript

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...of sees done: true immediately and runs zero times.
  • Driving the protocol by hand with next() and never calling return() when you stop. The source's finally never 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.

Up nextThe Prototype ChainIteration and Generators

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…