Generator 应避免同步阻塞,需将长耗时逻辑拆分为小块并 yield 分片执行,结合微任务让出控制权;CPU 密集型任务应移至 Web Worker;高频 yield 需缓存结果、简化返回值或改用状态机。

核心思路是:不让 Generator 本身承担同步计算压力,而是把长耗时逻辑拆出、移交或降级处理,确保每次 next() 调用都轻量、可中断。
避免在 yield 前堆积大量同步代码
Generator 的暂停点只在 yield 处生效。如果在两个 yield 之间写了一大段循环、递归或复杂计算(比如遍历 10 万条数据并做字符串拼接),这段代码会完全同步阻塞主线程,和普通函数无异——此时事件循环无法介入,宏任务(如 setTimeout、UI 渲染)就会被严重延后。
建议做法:
- 把长同步逻辑拆成小块,每处理一批就
yield一次,主动让出控制权 - 用
setTimeout(() => {}, 0)或Promise.resolve().then()把下一批推入微/宏任务队列,实现“分片执行” - 示例:处理数组时不用
for (let i = 0; i 一气呵成,而改用 <code>yield* chunkedProcess(arr, 100),每次只处理 100 项
用微任务桥接,不阻塞渲染与用户交互
如果必须做中等强度的同步工作(如格式化几千行 JSON),可借助微任务链,在每次 yield 后插入一个 Promise.resolve().then(),让浏览器有机会执行 UI 渲染和响应事件。
这样做的效果是:虽然仍在主线程运行,但不会连续霸占执行栈超过 16ms(即一帧时间),避免页面卡顿。
关键点:
- 不要在 Generator 内部直接调用
await Promise.resolve()(这会进入微任务,但仍是 Generator 自身流程) - 更稳妥的方式是:外部驱动,每次
gen.next()后手动加一层.then(() => nextStep()),把控制权交还事件循环 - 适合搭配
async function封装 Generator,形成async function runGen(gen) { ... }模式
将真正耗时操作移出主线程
对于 CPU 密集型任务(如图像处理、加密解密、大型数组排序),Generator 无法解决根本问题——它只是语法糖,不改变执行线程模型。
可行路径:
- Web Worker:把长任务放到独立线程,通过
postMessage与主线程通信;Generator 可用来管理 worker 的状态流转(如yield await workerResult) - 使用
Atomics.wait()+ SharedArrayBuffer(需 HTTPS)做协作式等待,但兼容性有限 - Node.js 环境下可用
worker_threads或child_process,Generator 作为协调层
用状态机替代深度嵌套的 yield 流程
高频 yield 本身不是问题,但若每个 yield 都触发一次复杂条件判断、对象深克隆或 DOM 查询,累积开销也会拖慢宏任务调度。
优化方向:
- 缓存中间结果,避免重复计算(例如把已处理的数据存入 Map,下次直接查)
- 用简单值(字符串、数字、布尔)代替复杂对象作为
yield返回值,减少 GC 压力 - 对高频调用的 Generator,考虑用状态机类(
class TaskMachine)替代,显式管理 state 和 transition,更可控也更易调试

















