Generators
Generators are a pattern in Javascript for producing values. They are interesting in that they allow a function to return a value whilst still running.
In terms of using generators, there’s not much difference between them and iterators. Here we will use them interchangeably.
Basics
Generators are often encountered as a way of iterating over data.
For example, we can iterate over the values or keys of a Map:
Once we have the generator/iterator, it’s common to use a for of
loop to run through them:
Or if it is asynchronous:
The downside of these loops is you’re sort of stuck in a very limited context. Sometimes you might need to manually step through an iterator. Deciding when and where to do so, instead of being locked into a loop.
For this, call next()
on it:
Using this pattern, we can grab a new item from the generator when needed. For example, imagine stepping through a generator each time the user taps a button. This would be harder to structure as a for of
loop.
Another option is ixfx’s Iterables.forEach
This pattern is succinct when combining generators:
Get all the data
If you want to read all the data from a generator into an array:
Async generator
Synchronous generator
Only do this if you know the generator will complete. Generators can be infinite, always producing a value. Instead use Iterables.toArray which can have limits for how many values to read or for how long.
Temporal
Flow.delayLoop is an asynchronous generator that delays its looping. It doesn’t return a usable value.
Accessing values over time
Flow.repeat repeatedly calls a function or generator, yielding the result. It can have optional delays as well as a limit of how many items to fetch
For example, to access the value of source
every second:
Producers
Some of the generators that produce values in ixfx are:
- Numbers.count: counts up integers, eg
count(3)
yields0, 1, 2
. - Oscillators
Forming generators
ixfx has some functions for specifically making a generator from various sources:
- Iterables.fromArray - yields values from an array at a given rate.
- Iterables.fromEvent - yields values from an event.
- Iterables.fromIterable - yields values from a source iterable at a given rate.
- Iterables.fromFunction - yields values using a function.
- Iterables.fromFunctionAwaited - yields values from an asynchronous function.
…but many ixfx functions will return a generator as a result.
From scratch
You can also write your own generator very easily, by marking your function with a ’*’.
This generator will return endless random numbers
If we access the generator manually, we essentially pull a value from it:
Our generator function looks dangerous in that there is a loop that never exits. But what is interesting about generators is that code essentially suspends at the yield
line until a value is requested.
In the above example, since we only request a value twice, our generator loop only runs twice.
Problems however occur if we use such an infinite generator in a for of
loop which will run until the generator exits:
One approach might be to limit the for of
loop:
Or to limit the generator: