yield in JavaScript: pausing a function and resuming it later

The yield keyword returns a value from a generator function and pauses it. How it works, delegation with yield*, and where generators actually earn their place.
3 min read
Believemy logo

An ordinary function runs to the end: it starts, computes, returns a result, and its job is over. A generator function can stop halfway, hand back a value, and wait until someone asks for the rest.

yield is the keyword marking those stopping points. It is the only construct in the language that lets a function keep its local variables between two calls without storing them somewhere else.


Definition

yield hands a value to the calling code and pauses the generator function containing it, whose execution will resume at that exact line on the next call to next().

A generator function is declared with a star: function* name(). Calling it runs nothing; it creates an iterator, an object carrying a next() method.

JAVASCRIPT
function* counter() {
  yield 1;
  yield 2;
  return 'done';
}

const it = counter();
it.next(); // { value: 1, done: false }
it.next(); // { value: 2, done: false }
it.next(); // { value: 'done', done: true }
it.next(); // { value: undefined, done: true }

Each call returns an object with two keys: the value handed back, and a flag telling you whether the function has reached its end.


What yield is not

KeywordEffect on the functionCan it resume
returnEnds it for goodNo
yieldPauses itYes, on the next next()
awaitPauses it until a promise settlesAutomatically

Worth noting: the value passed to return closes the series but is not part of it. A Spread (...) over this generator gives [1, 2], without the 'done'.


Endless sequences and delegation

Since nothing is computed before it is asked for, a generator function can describe an endless sequence without ever exhausting memory.

JAVASCRIPT
function* idSequence() {
  let n = 1;
  while (true) yield n++;
}

const ids = idSequence();
ids.next().value; // 1
ids.next().value; // 2

The star also delegates: yield* hands over to another generator, or to any iterable value, and yields all of its values before carrying on.

JAVASCRIPT
function* inner() {
  yield 'a';
  yield 'b';
}

function* outer() {
  yield 'start';
  yield* inner();
  yield 'end';
}

[...outer()]; // ['start', 'a', 'b', 'end']
Good to know

Communication runs both ways. The value passed to next() becomes the result of the waiting yield, which lets you write a function that asks a question, pauses, and resumes with the answer.


Frequently asked questions

Question

What is this actually good for?

For sequences whose items you do not want to compute up front: paging through an API, reading a very large file chunk by chunk, unique identifiers. A generator produces what is asked for, when it is asked for, where an Array would require building everything first.


Question

Can yield be written outside a generator function?

No, the file will not load: the keyword only means something inside a function declared with a star. The same error often comes from placing it in a nested arrow function, which cannot be a generator.


Question

Do I need to master generators to work in JavaScript?

They are rarely written by hand, but you do meet them: asynchronous iterators, walked with for await, are built on them, and some state-management libraries use them to describe sequences of steps. Being able to read a function* is plenty before you ever have to write one.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.