前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库外部停止生成器 throw return
JavaScript函数与作用域

怎么从外部停掉一个生成器,或者往里面抛一个错误?

停止用 it.return(value),它相当于在当前暂停的 yield 处执行了一句 return value,finally 里的清理代码照样会跑。抛错用 it.throw(err),它相当于在 yield 处 throw err,生成器内部能 catch 住就继续运行,没 catch 就抛给调用方,生成器随之结束。

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

从外面控制生成器的三个方法

  1. next(v)正常恢复,v 作为 yield 表达式的结果
  2. return(v)在暂停处插入 return v,经过 finally 后结束
  3. throw(e)在暂停处插入 throw e,交给附近的 try...catch

这三个方法都只作用于已经停在某个 yield 上的生成器。还没开始执行时调用 return() 或 throw(),生成器直接结束,函数体里的 try 根本来不及生效。

核心回答

先记住这个答案

生成器对象除了 next(),还有 return() 和 throw() 两个方法,都能从外部改变它的执行。it.return(value) 让生成器在当前暂停的 yield 处像执行了 return value 一样结束,如果外面包着 try...finally,finally 会先执行,最后返回 { value, done: true }。it.throw(err) 让暂停的 yield 表达式变成抛出 err,生成器内部有 try...catch 就能接住并继续执行下去;没接住的话,错误会从 it.throw() 这一行抛到外面,生成器也跟着结束。

  • return(v) 在暂停处执行 return v,会先走 finally
  • throw(e) 在暂停处抛错,内部能 catch 就继续
  • 没被 catch 的错误从 it.throw() 这一行抛出来
  • for...of 里 break 会自动调用 return()

先抛一个错误,再停掉它

把两个方法放在一个例子里,顺序看执行结果。

throw 被内部接住,return 触发 finallyJavaScript
function* worker() {
  try {
    yield '准备好了'
  } catch (err) {
    yield `接住了:${err.message}` // 接住后还能继续 yield
  } finally {
    console.log('清理资源')
  }
  return '正常结束'
}

const it = worker()
console.log(it.next().value)
console.log(it.throw(new Error('网络断了')).value)
console.log(JSON.stringify(it.return('被外部停止')))
console.log(JSON.stringify(it.next())) // 已经结束
查看输出与解释
准备好了
接住了:网络断了
清理资源
{"value":"被外部停止","done":true}
{"done":true}

第一次 next 跑到 yield '准备好了' 停住。it.throw() 相当于让这个 yield 抛出错误,被 catch 接住,生成器没有结束,继续跑到 catch 里的 yield 又停住,所以 throw() 的返回值就是这次 yield 的值。 it.return('被外部停止') 在 catch 里的 yield 处插入了 return,要离开 try 结构就必须经过 finally,所以先打印「清理资源」,然后返回 done: true。函数体末尾的 return '正常结束' 永远不会执行。最后一行输出只有 done,是因为结束后 next() 返回的 value 是 undefined,被 JSON.stringify 省略了。

没被接住的错误去了哪

如果生成器暂停的位置外面没有 try...catch,it.throw(err) 注入的错误就会从生成器里冒出来,从调用 it.throw() 的地方抛出,调用方需要自己 try...catch。这时生成器已经结束,之后 next() 只会返回 done: true。

生成器还没开始时调用
如果创建完生成器一次 next() 都没调用,就直接调 it.throw(err),函数体还没进入 try,内部的 catch 根本不会生效,错误会直接抛给调用方。it.return(v) 同理,直接返回 { value: v, done: true },finally 也不会执行。
finally 里再 yield 会怎样
finally 里如果写了 yield,调用 it.return(v) 时会先停在这个 yield 上,返回的是 done: false,还要再调一次 next() 才真正结束并拿到 v。这会让「停止」变成两步,清理代码里别写 yield。
回答前,多想一步

容易答错的地方

以为 return() 会跳过 finally
return() 走的是正常的退出流程,和函数体里写 return 一样要经过 finally。这正是它的价值:外部提前停止时,生成器里打开的资源依然能被释放。
以为 throw() 一定会让生成器结束
内部接住了错误,生成器就会继续运行,throw() 的返回值就是下一个 yield 的结果。只有错误没被接住时,生成器才会结束。
试着用自己的话回答

面试官还会怎么问?

for...of 中途 break,生成器会怎样?

for...of 在 break、return 或循环体抛错提前退出时,会自动调用迭代器的 return()。所以生成器的 finally 会执行,可以在这里关闭连接、释放锁。循环正常跑完则不会调用 return(),因为生成器自己已经结束了。

return() 能取消生成器里正在进行的网络请求吗?

不能。return() 只是让生成器在暂停点结束,已经发出去的请求不受影响。要取消请求,得在 finally 里调用对应的取消手段,比如 controller.abort()。

redux-saga 里是怎么用这两个方法的?

saga 中间件会在 yield 出去的 Promise 失败时调用 it.throw(err),所以 saga 里可以用普通的 try...catch 处理异步错误。任务被取消时则调用 it.return(),finally 里可以用 cancelled() 判断是不是被取消的。

从一道题,走向一组知识

把知识连起来

函数与作用域

生成器里 yield 和 return 有什么区别?return 之后还能继续 next 吗?

外部调用 return(v) 和函数体里写 return v 效果一样,都返回 done: true 并关闭生成器。

函数与作用域

var 和 let 都会提升吗?为什么 let 在声明前访问会报错?

生成器暂停时局部变量都保留在它的作用域里,let 声明的变量在 finally 里仍可以用来做清理。

参考资料

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

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

本题目录
  1. 先记住这个答案
  2. 先抛一个错误,再停掉它
  3. 没被接住的错误去了哪
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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