JavaScript生成器函数中条件yield的执行问题排查
问题分析与解决方案
问题根源
你的代码主要有三个核心问题,导致RL-type的标题无法正确生成:
- 生成器循环逻辑错误:
CommentGenerator里的while(typeof v !== 'undefined')循环一旦进入,就会一直输出同一个RL标题。因为生成器内部的v变量只会保留第一次next(r)传入的值,后续next()传进来的新值不会更新这个变量,循环也就无法输出新的标题。 - 调用逻辑匹配错误:你现在对每一行RL类型的内容都调用
gen.next(r),但实际上每个RL组(比如RL1开头的所有行)只需要输出一次标题,而且初始r=3也不符合预期输出从RL1开始的要求。 - 阶段划分不清晰:生成器没有明确区分「输入/层阶段」「随机层阶段」「输出阶段」,导致无法在正确的时机切换标题输出逻辑。
修正后的代码
调整生成器函数
重写CommentGenerator,让它能清晰接收RL组编号、切换阶段:
function* CommentGenerator() { // 输出固定的输入和层标题 yield '# Input 1\n'; yield ''; yield ''; yield '# Layer 1\n'; yield ''; yield '# Layer 2\n'; // 等待接收RL组编号,直到传入null结束RL阶段 let receivedValue; while ((receivedValue = yield) !== null) { // 收到组号后,输出对应的RL标题 yield `# RLayer ${receivedValue}\n`; } // RL阶段结束,输出输出层标题 yield '# Output 1\n'; // 后续一直输出空行 while(true) { yield ''; } }
调整调用逻辑
修改PrintStuff函数,跟踪RL组的变化,只在新组出现时触发标题输出,并正确切换阶段:
function PrintStuff() { var gen = CommentGenerator(); var out = ''; // 先走完生成器的固定初始标题部分 let result; do { result = gen.next(); out += result.value; } while (!result.done && !result.value.includes('# Layer 2')); // 初始化数据数组 var lines = ['I1', 'I1.1', 'I1.2', 'L1', 'L1.2', 'L2']; // 随机添加RL类型数据 const rlCount = Math.floor(Math.random() * 10) + 1; for(let i = 1; i <= rlCount; i++) { lines.push(`RL${i}`); lines.push(`RL${i}.1`); lines.push(`RL${i}.2`); lines.push(`RL${i}.3`); } // 添加输出类型数据 lines.push('O10'); lines.push('O10.1'); lines.push('O10.2'); let currentRLGroup = null; let rlNumber = 1; // 从RL1开始计数 for(let i = 0; i < lines.length; i++) { const line = lines[i]; if(line.startsWith('RL')) { // 提取当前RL的组号(比如RL1.1的组号是1) const group = line.match(/RL(\d+)/)[1]; if (group !== currentRLGroup) { // 遇到新的RL组,先推进生成器到接收值的位置,再传入组号获取标题 gen.next(); out += gen.next(rlNumber).value; currentRLGroup = group; rlNumber++; } else { // 同一组的子行,输出空行 out += gen.next().value; } out += `${line}\n`; } else if(line.startsWith('O')) { // 进入输出阶段,通知生成器结束RL阶段 gen.next(null); // 获取输出标题 out += gen.next().value; out += `${line}\n`; // 处理剩余的O类型子行 for (let j = i + 1; j < lines.length; j++) { out += gen.next().value; out += `${lines[j]}\n`; } break; // 已处理完所有O行,跳出循环 } else { // I/L类型行,输出空行+内容 out += gen.next().value; out += `${line}\n`; } } console.log(out) } PrintStuff();
关键改动说明
- 生成器的阶段化设计:把生成器分成三个明确阶段,通过
yield接收参数来切换RL阶段的输出,用null标记RL阶段结束,进入输出阶段。 - RL组跟踪:在调用端通过正则提取RL组号,只在新组出现时才触发生成器输出标题,避免重复输出。
- 初始阶段预执行:先把生成器的固定标题部分执行完,再开始处理数据行,确保初始标题顺序正确。
这样运行代码就能得到你想要的预期输出了。
内容的提问来源于stack exchange,提问作者Swiffy
相关产品推荐
相关产品推荐

