← 返回题目列表

Generator 函数是什么?yield 有什么作用?

高频 困难 第 18 / 28 题 更新于 2026/07/27
ES6Generatoryield迭代器

简化版

Generator 是可以暂停和恢复执行的函数,用 function* 声明,用 yield 产出值并暂停。调用 Generator 不会立即执行函数体,而是返回迭代器,通过 next() 推进执行。

详细版

示例:

function* gen() {
  yield 1;
  yield 2;
  return 3;
}

const it = gen();
it.next(); // { value: 1, done: false }
it.next(); // { value: 2, done: false }
it.next(); // { value: 3, done: true }

Generator 常用于自定义迭代器、惰性序列、异步流程控制。yield 既能向外产出值,也能接收下一次 next(value) 传回来的值。

完整版教学

一、Generator 是可暂停函数

普通函数一旦调用,会从头执行到结束。Generator 调用后只返回迭代器,函数体还没执行。每次调用 next(),函数执行到下一个 yield 暂停。

这种“暂停点”让函数可以分批产出数据。

二、yield 的两个方向

yield 右边的表达式会作为当前 next() 的返回值:

yield 1;

下一次调用 next(value) 时,传入的 value 会成为上一个 yield 表达式的结果。

这个双向通信机制让 Generator 能做更复杂的流程控制。

三、和迭代协议的关系

Generator 返回的对象实现了迭代器协议,所以可以用于 for...of

for (const x of gen()) {
  console.log(x);
}

注意 for...of 不会拿到 done: true 时的 return 值。

四、实际使用场景

现在异步流程更多用 async/await,但 Generator 仍常用于:

  • 自定义可迭代对象。
  • 惰性生成大量数据。
  • Redux-Saga 等库的副作用控制。

它的价值是把“生成数据”和“消费数据”的节奏分开。

五、面试追问与工程落地

Generator 常见追问是 yield*。它可以把另一个可迭代对象委托给当前 Generator,相当于把子序列展开到当前序列中。递归遍历树、组合多个迭代源时很有用。

还可能追问 Generator 和 async/await 的关系。早期异步流程控制可以用 Generator 加执行器,把 yield 出来的 Promise 等待后再继续 next;async/await 可以看作这类模式的语言级封装,语义更直接。

工程里 Generator 不如 Promise、async/await 高频,但理解它能帮助你看懂 Redux-Saga、惰性遍历、可迭代协议。面试时不要只说“很少用”,要能说明它的暂停恢复能力解决了什么抽象问题。

六、用状态机推演 next、throw 与 return

Generator 对象可理解为 suspendedStart → suspendedYield → completed 的状态机。第一次 next(value) 只是启动函数,传入的 value 没有前一个 yield 可以接收,因此会被忽略;后续 next(value) 才把值送回上一次暂停的 yield 表达式。每次调用返回统一的 { value, done },而 return 语句的值对应最终 done: true 的结果。

function* task() {
  try {
    const input = yield 10
    return input * 2
  } finally {
    console.log('cleanup')
  }
}
const it = task()
it.next(99) // { value: 10, done: false },99 被忽略
it.next(7)  // { value: 14, done: true }
操作注入生成器的完成类型常见用途
next(v)普通完成继续并把 v 交给上个 yield
throw(e)抛出完成在暂停点抛错,可被内部捕获
return(v)返回完成提前结束,并执行途经的 finally

yield* iterable 会委托给另一个迭代器,并转发 nextthrowreturn 协议,而不只是把若干值做语法展开。若只消费前 2 项就退出 for...of,迭代器的 return 还可获得清理资源的机会。

Generator 的重点不是背诵“可以暂停”,而是能沿着每次恢复时传入的完成类型解释值、异常和清理流程。

七、常见误区与追问

  • 误区:调用 Generator 函数会立刻执行函数体。 调用只创建迭代器,首次 next() 才开始执行。
  • 误区:第一次 next 传入的参数会成为第一个 yield 的结果。 第一次调用前没有暂停中的 yield 接收它,所以该参数被忽略。
  • 误区:yield 和 return 的结果没有区别。 yield 通常返回 done: false 并可恢复,return 完成后返回 done: true
  • 追问:Generator 为什么能被 for…of 遍历? 生成器对象实现迭代器协议,其 Symbol.iterator() 返回自身并持续提供 next() 结果。
  • 追问:throw 会发生在什么位置? 它把异常注入当前暂停的 yield 位置,内部 try/catch 有机会处理。
  • 追问:提前 return 会跳过 finally 吗? 不会,控制流会按正常语义执行途经的 finally,因此可用于清理。
  • 追问:yield 的最终表达式值是什么?* 当被委托迭代器结束时,yield* 表达式取得其最终返回值,而不是最后一次产出的普通值。

八、加强记忆

Generator 可以记成“带暂停键的函数”。yield 是暂停点,也是产出点;next() 是继续按钮。它天然实现迭代器,适合惰性序列和流程控制。

再配合 nextthrowreturn 三种恢复方式推演一次,Generator 的控制流就会从口诀变成可验证的状态机。