Functions: The Next Generator-tion

Generators

What are they?

Generator functions are functions that
can be executed in stages, and which
will maintain any internal state across
individual calls, exit control back to
consuming code wherever they're
told to exit, and start their execution
right back at the same spot when
they're called for their next step.

Huh?

Generator functions can stop and start

any number of times, depending on

how they're written, and they

remember where they left off.

Why would I need that?

Generators can assist in such things as:
 

  • State management
  • Infinite series generation

State Management

Text

const stateGenerator = function * () {
  let state = {};

  for (;;) {
    state = Object.assign(
      {},
      state,
      yield state
    );
  }
};

const state = stateGenerator();

state.next().value; // {}
state.next().value; // {}
state.next({ foo: true }).value; // { foo: true }
state.next().value; // { foo: true }
state.next().value; // { foo: true }
state.next({ bar: false }).value; // { foo: true, bar: false }
state.next().value; // { foo: true, bar: false }
state.next().value; // { foo: true, bar: false }
// etc

Infinite Series Generation

const fibonacciGenerator = function * () {
  let firstNum = 0;
  let secondNum = 1;
  
  yield 1;
  
  while (true) {
    const nextNum = firstNum + secondNum;
    firstNum = secondNum;
    secondNum = nextNum;
    yield nextNum;
  }
};

const fibonacci = fibonacciGenerator();

fibonacci.next().value; // 1
fibonacci.next().value; // 1
fibonacci.next().value; // 2
fibonacci.next().value; // 3
fibonacci.next().value; // 5
fibonacci.next().value; // 8
// etc

Async Generators

What are they?

const asyncRandomNumbers = async function * () {
  const url =
    'https://www.random.org/decimal-fractions/?num=1&dec=10&col=1&format=plain&rnd=new';

  while (true) {
    const response = await fetch(`${url}&cb=${Math.random()}`);
    const text = await response.text();

    yield Number(text);
  }
};

const example = async () => {
  for await (const randomNumber of asyncRandomNumbers()) {
    console.log(randomNumber);
    if (randomNumber > 0.95) break;
  }
};

Iterables

Iterables

Iterables are a defined interface that

include the return of 2 properties in a

yielded response: done, and value.
The done property tells the consumer

when a generator function has finished

and returned, while the value property

tells the consumer what the current

value of the generator function is.

Iterables

If manually nudging a generator function

along from step to step, consumers will

need to inspect the done property if

that aspect is important. A generator

can only run from start to finish once

per invocation. If you need to perform

the work over again, you'll need to

invoke the generator all over

again and step through it.

Iterables

Iteration constructs (for, while, do/while,

etc), will automatically interpret the done

value, in order to know when to exit the

loop. This holds true for async interables.

Symbol.iterator

This is a special symbol that allows you to

define a custom iterator on an object. This

will allow you to use general iteration

constructors (for, while, do/while,

etc.) to iterate over your object

in a more simplistic way.

Symbol.iterator

const Collection = class {
  constructor () {
    this._records = [];
  }

  add (value) {
    this._records.push(value);
  }

  get () {
    return this._records;
  }

  [Symbol.iterator]() {
    const records = this._records;
    let index = 0;

    return {
      next: () => ({ value: records[index++], done: index > records.length }),
    };
  };
};

Generator Support

Async Generator Support

Resources

fn.

Functions: The Next Generator-tion

By Richard Lindsey

Functions: The Next Generator-tion

  • 174