Difference Between yield and yield*

· 2 min read · 547 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.

yield 关键字用来暂停和恢复一个生成器函数((function*遗留的生成器函数)。

yield*

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

yield* 表达式用于委托给另一个generator 或可迭代对象。

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.

    你可以使用内置的 yield* 操作符来组合多个 Sagas,使得它们保持顺序。 这让你可以一种简单的程序风格来排列你的 宏观任务(macro-tasks)

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