Difference Between yield and yield*

Jan 15, 2021 · 2 min read · 398 Words · -Views -Comments

My understanding of JS generator functions was lacking. I hit a wall recently, so I studied and took notes.

yield vs yield*

yield

The yield keyword is used to pause and resume a generator function or legacy generator function.

The yield keyword is used to pause and resume a generator function (see function* or legacy generator functions).

yield*

The yield* expression is used to delegate to another generator or iterable object.

The yield* expression delegates to another generator or iterable object.

Example

 function* sub() {
        for (let i = 65; i < 70; i++) {
          yield String.fromCharCode(i);
        }
      }
      function* main() {
        yield 'begin';
        yield sub();
        yield '---------';
        yield* sub();
        yield 'end';
        return 'main end';
      }

      for (const i of main()) {
        console.log(i);
      }

From the console output we can see:

  1. yield and yield* are different.
  2. yield sub() returns the sub iterator, while yield* sub() yields each item from the sub iterator.

I think of the asterisk as “delegate all”: yield* delegates each item of the expression, whereas yield delegates the iterator as a whole.

Also note: the main generator has a return value that wasn’t printed. That’s because for...of cannot access the final return value. If we rewrite it, we can retrieve it:

const res = main();
      let value = null;
      while (value !== undefined) {
        value = res.next().value;
        if (value !== undefined) {
          console.log(value);
        }
      }

![image-20210122170503864](/Users/qhe/Library/Application Support/typora-user-images/image-20210122170503864.png)

Usage in Redux‑Saga

  • In practice, I use generators most often in Redux‑Saga effects. In some cases, yield and yield* can appear to behave the same.

  • The official docs’ explanation of the difference is brief — basically just noting they’re different:

    You can use the builtin yield* operator to compose multiple Sagas in a sequential way. This allows you to sequence your macro-tasks in a procedural style.

    You can use the built-in yield* operator to compose multiple Sagas sequentially, which lets you arrange your macro-tasks in a simple procedural style.

My understanding

  • In sagas, most side effects we orchestrate are async (macro‑tasks), so ordering matters.
    • If we must ensure all async in effect A — including async inside effect B that A calls — runs in sequence, use yield*. If A only delegates to a single B, then yield vs yield* often results in the same outcome.

Example

With Promises

Promises were introduced to solve callback hell in async programming.

Iterators and Generators

Final Thoughts

References

Authors
Developer, digital product enthusiast, tinkerer, sharer, open source lover