Skip to main content

Yield in generators

1. What yield does

yield is an operator that returns a value from a generator function to the outside and pauses execution until the next call to .next().

That is:

  • when the generator "reaches" yield, it freezes;
  • when we call .next() again, it resumes right after the yield where it stopped.

2. The simplest example

javascript
function* gen() { console.log('Before the first yield'); yield 1; console.log('Between yields'); yield 2; console.log('After the second yield'); } const it = gen(); console.log(it.next()); // { value: 1, done: false } console.log(it.next()); // { value: 2, done: false } console.log(it.next()); // { value: undefined, done: true }

What happens step by step:

  1. gen() returns an iterator object -> the function has not started yet.
  2. it.next() -> starts the function -> reaches yield 1, returns { value: 1 } and freezes.
  3. The next it.next() -> continues from the same place, after yield 1.
  4. After the second yield it "freezes" again.
  5. When done: true, the generator has finished.

3. How yield returns a value

javascript
function* seq() { yield 'A'; yield 'B'; yield 'C'; } const it = seq(); console.log(it.next().value); // "A" console.log(it.next().value); // "B" console.log(it.next().value); // "C" console.log(it.next().done); // true

yield is a "temporary return": it returns a value but does not finish the function.


4. Passing a value back into the generator via next(value)

yield not only returns data to the outside, it can also receive a value back on the next call to .next(value).

javascript
function* dialog() { const name = yield 'What is your name?'; yield `Hello, ${name}!`; } const chat = dialog(); console.log(chat.next().value); // "What is your name?" console.log(chat.next('Tim').value); // "Hello, Tim!"
  • The first next() started the generator and reached the first yield.
  • The second next('Tim') passed 'Tim' into the generator, and that value ended up in const name.

5. Finishing the generator via return

When the generator reaches the end, or if you call iterator.return(value), it finishes execution with done: true.

javascript
function* numbers() { yield 1; yield 2; } const it = numbers(); console.log(it.next()); // { value: 1, done: false } console.log(it.return('stop')); // { value: 'stop', done: true } console.log(it.next()); // { value: undefined, done: true }

6. yield* - delegating to another generator

Sometimes one generator can "hand over control" to another via yield*.

javascript
function* inner() { yield 'B'; yield 'C'; } function* outer() { yield 'A'; yield* inner(); // hands control over to another generator yield 'D'; } for (const val of outer()) { console.log(val); }

Output:

javascript
A B C D

yield* is a nested loop: "just yield all the values of another generator".


7. Important point - "laziness"

yield makes generators lazy - values are computed only on demand, not in advance.

javascript
function* range(start, end) { for (let i = start; i <= end; i++) { console.log('Generating', i); yield i; } } for (const num of range(1, 3)) { console.log('Received:', num); }

Output:

javascript
Generating 1 Received: 1 Generating 2 Received: 2 Generating 3 Received: 3

The generator "creates" values as needed, instead of storing the whole range at once.


8. Errors inside a generator (throw)

You can "throw" an error right inside the generator:

javascript
function* gen() { try { yield 1; } catch (e) { console.log('Error caught:', e.message); } } const it = gen(); it.next(); it.throw(new Error('Something is wrong')); // Error caught: Something is wrong

Summary

FeatureDescription
What it doesPauses execution and returns a value
ResumingVia .next()
Can pass values backYes (next(value))
Can be finishedVia return()
Can be delegatedVia yield*
EvaluationLazy
Works only infunction* (generators)

Short Answer

Interview ready
Premium

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