生成器函数用 function* 定义,调用返回 Generator 对象而非执行函数体;首次调用 .next() 才开始执行,yield 暂停并双向传值;支持 return、throw、return 方法控制退出与异常。

JavaScript 生成器函数怎么定义和调用?
生成器函数不是普通函数,它返回一个 Generator 对象,这个对象是可迭代的、可暂停/恢复的。定义时必须用 function* 语法(星号紧贴 function 关键字,不能有空格),调用后不立即执行函数体,而是返回一个生成器实例。
常见错误:写成 function *myGen()(星号前有空格)或 function myGen*()(星号位置错),会导致语法错误;或者直接调用 myGen() 后试图取返回值,却发现返回的是 Generator 对象而非预期结果。
-
function*是必需语法,*属于函数声明的一部分,不是修饰符 - 调用生成器函数(如
gen())只创建并返回生成器对象,**不执行任何yield行** - 真正开始执行要靠第一次调用
.next() - 生成器对象本身不可被 JSON.stringify,也不支持展开运算符直接解构(需先遍历)
yield 是如何暂停和传值的?
yield 不是返回值后结束,而是“暂停执行,并把右侧表达式的值作为 { value: ..., done: false } 中的 value 返回”。下次调用 .next() 时,从 yield 下一行继续,且上一次 .next(arg) 传入的 arg 会成为当前 yield 表达式的计算结果(即赋给左侧变量)。
容易忽略:第一次 .next() 传参会被忽略(因为还没走到任何 yield 等待接收),只有后续调用才生效。
function* counter() {
let count = 0;
while (true) {
const step = yield count; // 暂停,返回 count;恢复时,step = .next() 传入的值
count += step || 1;
}
}
const gen = counter();
gen.next(); // { value: 0, done: false }
gen.next(5); // { value: 5, done: false } → step = 5,count 变成 5
gen.next(); // { value: 6, done: false } → step = undefined,count 变成 6
生成器退出和异常处理要注意什么?
生成器可通过 return 提前结束(此时 done: true,value 为 return 的值),也可被 .throw() 强制抛出异常——如果生成器内部用 try...catch 捕获了,就不会终止;否则生成器立刻关闭,后续 .next() 全部返回 { value: undefined, done: true }。
本文档主要讲述的是Python开发网站指南;HTML是网络的通用语言,一种简单、通用的全置标记语言。它允许网页制作人建立文本与图片相结合的复杂页面,这些页面可以被网上任何其他人浏览到,无论使用的是什么类型的电脑或浏览器 Python和其他程序语言一样,有自身的一套流程控制语句,而且这些语句的语法和其它程序语言类似,都有for, if ,while 类的关键字来表达程序流程。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
-
.return(value)会强制结束生成器,返回{ value, done: true },跳过剩余yield -
.throw(err)把错误注入当前暂停点,等效于在那个yield行抛出err - 没捕获的异常会让生成器进入
completed状态,不能再继续 - 使用
for...of遍历时,内部自动调用.next(),但不会触发.throw()或.return(),异常会冒泡到循环外
实际项目中哪些场景适合用生成器?
生成器的核心价值是“可控的、带状态的迭代逻辑”,不是为了替代 async/await(虽然早期曾被用于手写协程)。现在典型用途集中在:自定义迭代器、状态机建模、配合 co 库处理异步(已过时)、以及某些算法需要分步产出(如树的深度优先遍历、无限序列生成)。
注意:现代代码中绝大多数异步场景应优先用 async/await;生成器若混用 Promise 又不借助运行时库(如 co),容易写出难以调试的“回调地狱变体”。
- 实现自定义
[Symbol.iterator]时,function*是最简洁方式(比如让一个类支持for...of) - 生成斐波那契、素数等无限序列时,
yield天然避免一次性计算全部 - 表单多步骤校验、游戏 AI 决策流程等状态流转复杂逻辑,可用生成器封装步骤与转移条件
- 不要用生成器替代
setTimeout或requestIdleCallback做节流——它不释放 JS 主线程
生成器的暂停/恢复机制依赖引擎调度,不是真正的多线程;一旦生成器内部陷入死循环或长时间同步计算,整个脚本仍会卡住。真正关键的,是理解 yield 的双向通信本质:它既向外输出值,也向内接收下一次的输入。










