前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库generator 生成器原理 yield 与 next
JavaScript函数与作用域

生成器函数是怎么工作的?yield 和 next 是什么关系?

调用生成器函数时函数体一行都不执行,只返回一个生成器对象。每调用一次 next(),函数体就从上次停下的地方跑到下一个 yield 再停住,返回 { value, done }。next(x) 传的参数,会变成上一个 yield 表达式的结果。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#函数与作用域
先看核心答案读代码示例
理解线索

yield 和 next 的一来一回

  1. yield value把 value 交给外面,函数暂停在这里
  2. next(x)让函数继续跑,x 成为刚才那个 yield 表达式的值
  3. { value, done }next 的返回值,done 为 true 表示函数跑完了

第一次 next() 时函数还没停在任何 yield 上,没有地方接收参数,所以第一次传的值会被丢掉。想给生成器初始数据,应该通过调用生成器函数时的参数传。

核心回答

先记住这个答案

生成器函数用 function* 定义,调用它不会执行函数体,而是返回一个生成器对象。每调用一次这个对象的 next(),函数体就从上次暂停的位置继续执行,直到遇到下一个 yield 再暂停,并返回 { value: yield 后面的值, done: false }。函数执行完或遇到 return 时返回 done: true。yield 和 next 是双向的:yield 把值交出去,next(x) 传进来的 x 会成为上一个 yield 表达式的结果。

  • 调用生成器函数只返回迭代器,函数体不执行
  • 每次 next() 跑到下一个 yield 暂停,局部变量都保留
  • next(x) 的参数是上一个 yield 的返回值
  • 第一次 next() 传的参数会被丢掉

一步步看 yield 和 next 怎么交替

生成器可以理解成一个能暂停的函数。外面每按一次「继续」,它就往前跑一段,交出一个值,然后停下等下一次「继续」。

用 next 传值给 yieldJavaScript
function* chat() {
  console.log('开始执行')
  const name = yield '你叫什么?' // 暂停,等外面传名字进来
  const age = yield `你好 ${name},几岁了?`
  return `${name} ${age} 岁`
}

const it = chat() // 这里不会打印「开始执行」
console.log('已创建')
console.log(it.next('没用').value) // 第一次 next,参数被丢掉
console.log(it.next('小明').value) // 小明 成为第一个 yield 的结果
console.log(JSON.stringify(it.next(18)))
查看输出与解释
已创建
开始执行
你叫什么?
你好 小明,几岁了?
{"value":"小明 18 岁","done":true}

执行顺序是这样的。调用 chat() 什么都没打印,说明函数体没执行。第一次 next 才开始执行,打印「开始执行」,跑到第一个 yield 停住,把问题交出来。这时传的 '没用' 没有地方接收,直接丢掉。 第二次 next('小明'),函数从第一个 yield 那里恢复,'小明' 就是这个 yield 表达式的值,赋给了 name,然后跑到第二个 yield 再停。第三次 next(18) 同理,age 拿到 18,接着遇到 return,返回 done: true。

暂停时函数的状态去哪了

普通函数执行完,局部变量就没了。生成器暂停时,整个执行现场都会保存在生成器对象里,包括局部变量的值、执行到了哪一行、try 块的嵌套关系。下次 next 就从这里接着跑。

生成器对象的几种状态
规范里生成器对象有几种状态:刚创建还没开始、停在某个 yield 上、正在执行、已经结束。一旦结束,再调用 next() 只会得到 { value: undefined, done: true },不能重新开始。要重新跑一遍,就再调用一次生成器函数,得到一个新对象。
生成器不是多线程
yield 暂停的是生成器自己,控制权交回给调用 next 的代码,整个过程都在同一个线程里同步完成。它能写出看起来像「一边算一边等」的代码,但不会并行执行任何东西。
回答前,多想一步

容易答错的地方

以为调用生成器函数就会执行到第一个 yield
调用只是创建生成器对象,函数体里第一行代码都不会跑。第一次 next() 才开始执行。
以为 next(x) 的 x 是当前 yield 的值
next(x) 的 x 是给上一个已经暂停的 yield 的。yield 右边的值是交出去的,左边接收到的是下一次 next 传进来的,方向正好相反。
试着用自己的话回答

面试官还会怎么问?

生成器在实际项目里用在哪?

最常见的是按需生成序列,比如无限的 ID 生成器、分页数据的逐页拉取,不需要一次把所有数据算出来。另一个是 redux-saga,它用生成器描述异步流程,yield 出一个描述副作用的对象,由框架执行完再用 next 把结果送回来。

生成器和 async/await 有什么关系?

async/await 出现之前,co 这类库就是用生成器模拟的:yield 一个 Promise,库等 Promise 完成后调用 next(结果) 把值送回去。async/await 可以看作把这套自动执行的逻辑做进了语言里。

return 的值 for...of 能拿到吗?

拿不到。for...of 遇到 done: true 就停止,不会把那一次的 value 当作元素。想拿 return 的值,只能手动调用 next 读最后一次的结果。

从一道题,走向一组知识

把知识连起来

函数与作用域

生成器对象和数组这种可迭代对象有什么不一样?

生成器对象同时实现了迭代器协议和可迭代协议,所以能直接用 for...of 遍历。

函数与作用域

生成器函数能用 new 调用吗?里面的 new.target 是什么?

调用生成器只是创建迭代器、不执行函数体,这也是它不能被 new 的原因之一。

参考资料

  • JavaScript:函数与作用域参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 一步步看 yield 和 next 怎么交替
  3. 暂停时函数的状态去哪了
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑