Published on

Generators in JavaScript

Let’s write a function that let’s us take an n-sized subset of some iterator.

function* take(n, iter) {
  let index = 0

  for (const x of iter) {
    if (index >= n) return

    yield x

const it = take(3, ['foo', 'baz', 'bar', 'doe', 'ray', 'me'])
printIterations(it) // foo, baz, bar


Imagine you have an array, and you want to cycle through all the values, ad infinitum.

function* cycle(array) {
  let index = 0

  while (true) {
    yield array[index]
    index = (index + 1) % array.length

const it = take(5, cycle([1, 2, 3]))
printIterations(it) // 1, 2, 3, 1, 2


Now imagine you’re a teacher, and you are going to select a student for a task. However, each time you count, you skip a student.

// To skip 1 student means to add 2 with each iteration
// To skip n students means to add n+1 with each iteration
function* skip(n, array) {
   * A teacher would count the first student in the line as "1",
   * and arrays are 0 indexed, so starting at -1 correct for that
   * Notice that if you skip 0 students, you start at the beginning
   * of the line, and count normally
  let index = -1

  while (true) {
    index = (index + (n + 1)) % array.length
    yield array[index]

const it = take(5, skip(1, ['Captain America', 'Black Widow', 'Hulk', 'Iron Man', 'Black Panther']))
// yes, your students are the Avengers.
Black Widow
Iron Man
Captain America
Black Panther

How many times did we have to count until we got back to the start of the array?

function* skipUntilMatch(n, array, toFind) {
  let index = -1
  let count = 1

  while (true) {
    index = (index + (n + 1)) % array.length

    if (array[index] === toFind) return count


const arr = ['Captain America', 'Black Widow', 'Hulk', 'Iron Man', 'Black Panther']
const it = skipUntilMatch(1, arr, arr[0])
exhaustAndGrabLast(it) // 3, i.e. "miney"


The functions were using above are called generators. They’re special functions that pause execution and yield a value. When they are executed the next() time, execution is resumed, as opposed to done over again, like a normal function. They are done when they finally return.

**Generators** are functions with the ability to pause and resume execution. A generator looks like a function but behaves like an iterator.

This gives us another way to iterate. One of the key functionalities provided is the ability to work with infinite series. When you iterate using a collection, all the values are sitting in memory, so you don’t have that ability.

function* naturalNumbers() {
  let num = 1

  while (true) {
    yield num

const it = take(7, naturalNumbers())
printIterations(it) // 1, 2, 3, 4, 5, 6, 7

/* or, if you don't want it to terminate */
printIterations(naturalNumbers()) // 1, 2, 3, 4, ...


Achilles is running a race. Each step is half the length of his previous step. How many steps until he’s not moving at all?

Theoretically, half of any number, ad infinitum, will never reach 0. Only it’s limit does.

However, in a programming language like JS, we’re dealing with finite resources, and that number will at some point reach 0. Let’s find out when.

function* halfUntilZero() {
  let remaining = 1
  let count = 0

  while (true) {
    if (remaining == 0) return count

    remaining = remaining / 2

exhaustAndGrabLast(halfUntilZero()) // 1075

Finally, let’s take a look at some of the helper functions we’ve been using. It might be useful to reflect on JavaScript’s iterator protocol.

function printIterations(it) {
  let i =

  while (!i.done) {
    i =

function exhaustAndGrabLast(it) {
  let current =
  let value = current.value

  while (!current.done) {
    current =
    value = current.value || value

  return value


  1. Understanding JavaScript Generators, inspired take and naturalNumbers
  2. MDN