Difference Between yield and yield*

Difference Between yield and yield*

Jan 15, 2021 · 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

Alan H
Authors
Developer, Tech Enthusiast, Open Source Advocate