Skip to main content

The function* keyword

The function* keyword creates a generator function, which does not run when you call it but instead returns a generator object (an iterator). That object lets you drive execution of the function by hand, through calls to .next(), .throw() and .return().

Theory

TL;DR

  • function* declares a generator; the asterisk goes right after the word function.
  • Calling a generator returns an iterator, not the result of a computation.
  • yield inside the body hands a value out and pauses execution until the next .next().
  • The generator object implements the iterator protocol, so it works in for...of.
  • next(value) passes a value back inside the function, into the result of the yield expression.
  • async function* returns an async iterator, which you walk with for await...of.

Quick example

javascript
function* gen() { yield 1; yield 2; yield 3; } const iterator = gen(); // the function does not run immediately console.log(iterator.next()); // { value: 1, done: false } console.log(iterator.next()); // { value: 2, done: false } console.log(iterator.next()); // { value: 3, done: false } console.log(iterator.next()); // { value: undefined, done: true }
  • The first gen() call returns an iterator, not a result.
  • Every .next() runs execution up to the next yield.
  • After the last yield the function finishes and reports done: true.

Syntax

javascript
function* functionName(params) { yield value1; yield value2; // ... }
  • The asterisk (*) after the word function makes the function a generator.
  • The yield keyword is used inside to pause execution and return an intermediate value.

function* name(), function *name() and function * name() are all equivalent, but the settled style is to keep the asterisk next to the word function.

How yield works

yield is a pause inside a generator function. It does three things:

  1. returns a value to the outside (the value field);
  2. pauses execution of the function;
  3. waits for the next .next() call to continue.
javascript
function* greet() { console.log('Start'); yield 'Hello'; console.log('Continuing'); yield 'How are you?'; } const it = greet(); console.log(it.next().value); // "Hello" console.log(it.next().value); // "How are you?" console.log(it.next()); // done: true

Between two yield statements execution really does stop, which is impossible to achieve with a regular function.

A generator is an iterator

The object returned by function* implements the iterator protocol, so you can pass it into for...of:

javascript
function* gen() { yield 1; yield 2; } for (const n of gen()) { console.log(n); }

Output:

javascript
1 2

Besides .next(), a generator object has two more methods: .return(value) finishes the generator early and yields { value, done: true }, while .throw(error) raises an error at the point of the current yield, so it can be caught inside the generator body with an ordinary try/catch.

How function* differs from a regular function

Featurefunctionfunction*
Returnsa result (value)an iterator (generator object)
Can pause executionNoYes, through yield
Runs immediatelyYesNo, only on .next()
Used forordinary operationslazy evaluation, iterators, streams
Can take values back inNoYes, through next(value)

Passing values back in, and the async variant

The argument of next(value) lands inside the generator as the result of the yield expression where execution was paused.

javascript
function* conversation() { const name = yield 'What is your name?'; yield `Hello, ${name}!`; } const chat = conversation(); console.log(chat.next().value); // "What is your name?" console.log(chat.next('Maria').value); // "Hello, Maria!"

The first next() starts the generator, the second passes 'Maria' back in, and that value lands in const name.

If you add async, you can use await inside the generator (ES2018):

javascript
async function* fetchChunks() { yield await Promise.resolve('Chunk 1'); yield await Promise.resolve('Chunk 2'); } for await (const chunk of fetchChunks()) { console.log(chunk); }

Async generators return an async iterator and are walked with for await...of.

Summary:

PropertyDescription
function*Declares a generator function
What it returnsAn iterator (an object with .next(), .throw(), .return())
Keyword used insideyield
Distinctive traitCode can be executed step by step and paused
Asynchronous variantasync function*
Main useIterators, lazy evaluation, data streams, complex asynchronous processes

Common mistakes

  • Expecting gen() to return a value. The call returns a generator object; to get a value you need .next().value.
  • Forgetting the asterisk. Without * the word yield in the body becomes a syntax error (in strict mode) or just an ordinary identifier.
  • Assuming the code before the first yield runs at call time. It only runs on the first .next().
  • Trying to use an arrow function. Arrow functions cannot be generators, there is no () => {} form with an asterisk; for object and class methods there is the shorthand *name() {}.
  • Ignoring .return() and .throw(). These are the standard ways to finish a generator early or to inject an error into it, not exotica.
  • Iterating an async function* with a plain for...of. You need for await...of, otherwise you get promises back.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.