<p>yield* 本身不被V8内联缓存(IC)优化,真正可被IC加速的是迭代器的.next()方法调用,前提是对象结构稳定且调用方式一致。</p>
yield* 后面跟自定义可迭代对象时,V8 的内联缓存(IC)并不直接参与优化——这不是它负责的环节。
内联缓存只作用于两类高频操作:
obj.x) obj.method()) 而 yield* 展开的是迭代协议([Symbol.iterator]() 返回的迭代器),整个过程走的是 迭代器状态机路径,由 V8 的生成器运行时(Generator Runtime)和迭代器协议实现共同处理,不触发 IC 机制。
yield* 的实际执行链条yield* iterable 会调用 iterable[Symbol.iterator]() .next() 方法) .next(),把每次返回的 value 逐个 yield 出去 .next() 调用本身 可能 受益于 IC ——但前提是: .next 是普通函数属性(非 getter、非 Proxy、非动态计算) yield* 出现在同一代码位置,且反复作用于同类迭代器 常见混淆点来自以下现象:
yield* 多次展开,性能很好 这表面像 IC 生效/失效,实则是:
.next() 调用是否能稳定命中单态 IC iter.next() 总是同一个隐藏类的对象方法,V8 就能内联该调用并缓存偏移 iter 类型多变(比如 yield* obj 有时是数组、有时是 Map、有时是手写迭代器),.next 调用退化为多态甚至 megamorphic,失去加速效果 yield* 实际受益于 IC确保迭代器对象满足 IC 友好条件:
next 方法),避免后续增删 Object.defineProperty 或 Proxy 包装迭代器(破坏隐藏类稳定性) yield* 前后穿插 iter['next']() 或 Reflect.get(iter, 'next')(污染该调用点的 IC 状态) 例如:
class RangeIterator { constructor(start, end) { this.start = start; // 提前声明 this.end = end; // 提前声明 this.current = start; // 提前声明 } next() { // 普通方法,非 getter if (this.current < this.end) { return { value: this.current++, done: false }; } return { done: true }; } [Symbol.iterator]() { return this; }}// ✅ 安全:每次 yield* 都面对同构迭代器function* gen() { yield* new RangeIterator(0, 100); yield* new RangeIterator(100, 200); // 同类对象,IC 可复用}
yield* 本身不被 IC 加速,它只是语法糖,背后是标准迭代协议调用 .next() 方法调用(前提是调用方式稳定、对象结构稳定) yield* 当作“黑盒加速点”是误解;优化重点应放在迭代器对象的构造一致性和.next() 访问模式的稳定性上 不复杂但容易忽略