yield 本身不提供动态分流能力,它仅是委托语法糖,真正的分流必须由调用方通过前置状态判断(如 if 或三元运算)选择子生成器,再用 yield 展开执行。

yield* 本身不提供“动态分流”能力,它只是语法糖,用于委托另一个可迭代对象(如生成器、数组、字符串等)产出值。真正的动态分流逻辑必须由 调用方控制流程,而非 yield* 自动完成。关键在于:把“前置状态判断”放在生成器外部或内部的控制流中,再结合 yield* 委托不同子清洗管道。
明确 yield* 的角色:委托,不是调度
yield* 的作用是将当前生成器的产出权完整移交——它不会中断、跳转、条件跳过或重定向。例如:
function* cleanA() { yield "a1"; yield "a2"; }function* cleanB() { yield "b1"; yield "b2"; }function* pipeline(state) { if (state === "A") yield* cleanA(); else yield* cleanB(); }
这里分流发生在 if 判断处,yield* 只负责把选中的清洗链“展开”进当前流。
在流式清洗中实现状态感知分流的推荐结构
建议采用“主生成器 + 状态驱动子生成器选择”的模式,保持可读性和可测试性:
- 每个清洗节点封装为独立生成器函数(如
function* dedupe(items)、function* validate(items, schema)) - 主清洗管道生成器接收初始数据和上下文状态(如
{ userRole: "admin", source: "api_v2" }) - 根据状态决定是否启用某段清洗逻辑,并用 yield* 插入对应子管道
- 避免在 yield* 行内做复杂判断;把分支逻辑提前收束到变量或函数调用
一个实用示例:按数据来源选择校验规则
假设输入是逐条 JSON 日志,需根据 source 字段选择不同清洗路径:
function* enrichLog(log) {
yield { ...log, timestamp: Date.now() };
}
<p>function* validateForWeb(log) {
if (!log.url) throw new Error("missing url");
yield log;
}</p><p>function* validateForMobile(log) {
if (!log.deviceId) throw new Error("missing deviceId");
yield log;
}</p><p>function* mainPipeline(logs, context) {
for (const log of logs) {
// 前置状态判断
const validated = context.source === "web"
? validateForWeb
: validateForMobile;</p><pre class="brush:php;toolbar:false;">// 动态委托:此处 yield* 接入的是运行时确定的生成器
yield* enrichLog(log);
yield* validated(log);} }
注意:validated(log) 返回的是生成器实例,yield* 才真正执行并产出。
注意事项与常见陷阱
- yield* 不会捕获子生成器抛出的错误——异常会向上冒泡,需在外层 try/catch 或交给消费方处理
- 不要试图在 yield* 后面直接跟 yield 来“混搭”不同来源——这会破坏流式语义;应统一用生成器抽象每段逻辑
- 若需“中途切换路径”,比如某条数据触发规则变更,应在主循环中重新计算下一阶段生成器,而不是靠 yield* 自动响应
- 调试时可对每个子生成器单独单元测试,确保其行为符合预期,再组合
不复杂但容易忽略:动态分流的本质是控制流决策,yield* 只是让这个决策后的链条平滑融入当前流。

















