Difference Between yield and yield*
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:
yield
andyield*
are different.yield sub()
returns the sub iterator, whileyield* 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);
}
}

Usage in Redux‑Saga
In practice, I use generators most often in Redux‑Saga effects. In some cases,
yield
andyield*
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, thenyield
vsyield*
often results in the same outcome.
- If we must ensure all async in effect A — including async inside effect B that A calls — runs in sequence, use
Example
With Promises
Promises were introduced to solve callback hell in async programming.