GGistDev

Iterators and Generators in JavaScript

Iterators define a standard way to step through data; generators make writing iterators easy.

Iterator protocol

An object is iterable if it has [Symbol.iterator]() returning an iterator with next().

const iter = {
  current: 0,
  [Symbol.iterator]() { return this },
  next() {
    if (this.current < 3) return { value: this.current++, done: false }
    return { value: undefined, done: true }
  }
}
for (const v of iter) {}

Generators

Use function* and yield to create iterators.

function* count(n) {
  for (let i = 0; i < n; i++) yield i
}
[...count(3)] // [0,1,2]

Generator communication

next(value) sends a value back to the generator; return ends it; throw injects an error.

Async iterators

Use async function* with for await..of for streams of promises.

async function* lines(stream) {
  for await (const chunk of stream) {
    yield* chunk.split('\n')
  }
}

Built-ins and helpers

  • Many built-ins are iterable: arrays, strings, maps, sets
  • Use spread (...iterable) and array from (Array.from(iterable)) to collect

Summary

  • Implement the iterator protocol or use generators for custom sequences
  • Use async generators and for await..of for asynchronous streams