LESSON 22 · INTERMEDIATE4 min read

The Iteration Protocols: Symbol.iterator, Iterables & Generator Functions

Unlock ECMAScript's iteration protocol. Create custom iterables, master generator functions (function*), and stream data lazily with yield.

ES2024 / Node.js 20+Free to readModule 6 of 10
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Implement the Iterable and Iterator protocols using Symbol.iterator and next().
  • Author generator functions (function*) and manage execution pauses via yield.
  • Stream infinite sequences and handle large datasets with constant O(1) memory.

01The Universal Iteration Protocols

Prior to ES2015, iterating over different data structures required disparate techniques: for-loops for arrays, for...in for objects, and index counting for DOM NodeLists. ES2015 unified iteration across the entire language through two formal contracts: the Iterable Protocol and the Iterator Protocol.

An object is Iterable if it implements a method whose key is Symbol.iterator. This method must return an Iterator object. An Iterator object implements a .next() method that returns an object with two properties: value (the current datum) and done (a boolean indicating if iteration has concluded). Any object implementing this contract automatically works with for...of loops, the spread operator (...), and Array.from().

The ECMAScript Iteration Protocol is composed of two distinct interfaces: the Iterable Protocol and the Iterator Protocol. An object is an Iterable if it implements a method keyed by Symbol.iterator that returns an Iterator.

An Iterator is an object that implements a .next() method returning a result descriptor ({ value: any, done: boolean }). This uniform interface allows the JavaScript runtime to consume arrays, strings, Maps, Sets, and custom streams using identical syntax: for...of loops, the spread operator (...), and Array.from().

example.js⚡JavaScript
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

02Generator Functions: Pausing Execution with Yield

Writing custom iterator objects with manual state tracking can be verbose. ECMAScript provides Generator Functions (declared as function*) as a syntax-level mechanism to write iterators effortlessly.

When you invoke a generator function, it does not execute its body immediately. Instead, it returns a Generator object, which conforms to both the iterable and iterator protocols. When .next() is called, the generator executes until it encounters a yield expression. It suspends execution, yields the value to the caller, and remembers its exact execution frame. Calling .next() again resumes execution immediately following the yield statement.

example.js⚡JavaScript
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

03Lazy Evaluation and Memory Optimization

The superpowers of generators are lazy evaluation and pulling data on-demand. Standard arrays eagerly compute and store all elements in memory immediately. If you need to process a 5-gigabyte log file with 10 million entries, attempting to load all lines into a standard array will crash with a memory heap exhaustion.

With a generator, values are computed only when requested by the consumer. Memory consumption remains strictly constant (O(1)) regardless of whether the dataset contains 10 items or 10 billion items.

example.js⚡JavaScript
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

04Why This Matters in Production

Generators are the hidden engine behind modern pagination streams, asynchronous saga architectures (Redux-Saga), and streaming Node.js pipelines. They allow you to write synchronous-looking code that pauses and resumes gracefully.

Whenever you are designing APIs that process unbounded streams of events, database cursor batches, or infinite sequences, build them with generators to ensure zero memory bloat.

LET IT CLICK

The ideas worth keeping.

  • Implement [Symbol.iterator] to make any custom data structure compatible with for...of and spread (...).
  • Generator functions (function*) pause execution with yield and resume seamlessly with .next().
  • Use generators for streaming and lazy evaluation to handle massive datasets with constant O(1) memory.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Exercise 1: Infinite Fibonacci Generator

Write a generator function fibonacciGenerator that yields Fibonacci numbers indefinitely on demand.

your_turn_1.js⚡JavaScript
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.jsJavaScript
function* fibonacciGenerator() {  let a = 0, b = 1;  while (true) {    yield a;    [a, b] = [b, a + b];  }}

The generator maintains a and b across yields, evaluating the sequence lazily as consumers invoke .next().

02

Exercise 2: Custom Iterable Tree Traversal

Implement [Symbol.iterator] on a Tree node object to traverse values in depth-first order.

your_turn_2.js⚡JavaScript
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.jsJavaScript
class TreeNode {  constructor(val, children = []) {    this.val = val;    this.children = children;  }  *[Symbol.iterator]() {    yield this.val;    for (const child of this.children) {      yield* child;    }  }}

Using yield* delegates iteration recursively to child iterables, creating a clean depth-first traversal with for...of.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01What method must an object implement to be compliant with the Iterable Protocol?
02What does the 'yield' keyword do inside a generator function?
03Why do generators consume constant O(1) memory when processing large datasets?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Exercise 1: Infinite Fibonacci Generator

Write a generator function fibonacciGenerator that yields Fibonacci numbers indefinitely on demand.

EXPECTED OUTPUT
[Process exited with code 0 - No output]
main.jsJavaScript
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock lesson completion.