JavaScript生成器手动调用正常,循环调用出现隐式步长异常
Generator循环调用值跳变的原因与修复方案
我编写了一个带有可选最大值参数的Generator函数numGen,代码如下:
function* numGen(start: number, stop?: number) { let n = start; if (stop) { while (n < stop) { const step: number = yield n; if (step) { n += step; } else { n++ } } } else { while(true) { const step: number = yield n; if (step) { n += step; } else { n++ } } } } const genObj = numGen(0, 15);
手动调用genObj.next()或指定步长调用时,输出均符合预期:
手动无步长调用示例
console.log(genObj.next()) console.log(genObj.next()) ...
输出:
{ value: 0, done: false } { value: 1, done: false } ... { value: 14, done: false } { value: undefined, done: true } ...
指定步长调用示例
let s = 3; console.log(genObj.next(s)) console.log(genObj.next(s)) ...
输出:
{ value: 0, done: false } { value: 3, done: false } ... { value: 12, done: false } { value: undefined, done: true } ...
但使用while循环调用时,无论是否指定步长,都会出现值跳变的异常:
无显式步长循环调用示例
while (genObj.next().done !== true) { console.log(genObj.next()) }
输出:
{ value: 1, done: false } { value: 3, done: false } ... { value: 13, done: false } { value: undefined, done: true }
显式步长循环调用示例
let s = 3; while (genObj.next(s).done !== true) { console.log(genObj.next(s)) }
输出:
{ value: 3, done: false } { value: 9, done: false } { value: undefined, done: true }
异常原因
核心问题在于循环条件里的next()调用会消耗一次生成器的输出:
- Generator的
next()方法每次调用都会推进生成器到下一个yield节点,返回当前节点的值,同时更新内部状态。 - 你在循环条件中调用
genObj.next()时,已经获取了一个值(比如第一次调用返回{value:0, done:false}),但没有处理这个值;进入循环体后又调用了一次next(),生成器再次推进,输出的是下一个值,相当于每轮循环跳过了一个结果。 - 带步长的场景同理:每次循环两次调用
next(s),生成器会连续执行两次步长累加,自然出现跳变。
修复方案
只需要将next()的调用结果存储起来,在循环中复用这个结果,避免重复调用next():
无显式步长的正确写法
let result; while (!(result = genObj.next()).done) { console.log(result); }
输出恢复正常:
{ value: 0, done: false } { value: 1, done: false } ... { value: 14, done: false }
带显式步长的正确写法
let s = 3; let result; while (!(result = genObj.next(s)).done) { console.log(result); }
输出恢复正常:
{ value: 0, done: false } { value: 3, done: false } { value: 6, done: false } { value: 9, done: false } { value: 12, done: false }
这种写法每轮循环只调用一次next(),既用返回结果判断循环是否继续,又在循环体内打印该结果,确保每个生成的值都被正确处理,不会被跳过。
内容的提问来源于stack exchange,提问作者Wasteland
相关产品推荐
相关产品推荐

