Generators

Generators are a kind of iterator introduced in ES6.

They are useful when the values that we want to iterate "are not the elements of a data structure, but the results of a computation" (Flanagan).

Creating a generator function

To create a generator, you have to create a generator function. A generator function returns a Generator object, which is an iterator.

To create a generator function, use the function* syntax. (In object method shorthand, you can simply prefix the name of the function with *, e.g. *myGenerator() {...}.)

It is only inside generator functions you can use the yield and yield* statements.

Calling a generator function

When you call a generator function, it returns a Generator object (an iterator), but does not execute the generator function's body.

It is when you call next() on the generator object, JavaScript will execute the generator function's body from the top (or wherever it stopped last) until it reaches the yield

yield and yield*

yield

This pauses the execution of the generator function.

Except for the first call of .next(), you can actually pass an argument to .next(). The argument that you pass to .next() will be evaluated as the value of the yield <something> expression.

yield*

This tells JavaScript to yield on each iterable value of the iterator given beside yield*. (Instead of yielding on a single value.)

return() and throw()

Instead of calling .next() on a generator object, you can also call the following functions to control the program flow in the generator function:

  • .return(value) to cause the generator function to return with the given value
  • .throw(error) to cause exception in the generator function

Example: the Range object revisited

This time, instead of writing the [Symbol.iterator] method that returns an iterator object manually, we will just convert it into a generator function.

References