应避免在主线程执行大对象深拷贝,改用分批yield、Web Worker或不可变更新等策略。优先使用structuredClone,禁用JSON.parse(JSON.stringify()),超大对象需BFS遍历防栈溢出。

大对象深拷贝卡住主线程,本质是同步递归遍历耗尽 CPU 时间片,UI 无法响应。关键不是“怎么拷得更快”,而是“别让主线程干这活”。
拆分任务,主动交还控制权
对大数组或长列表,不一次性深拷贝全部,而是按批次处理,每批后用 setTimeout 或 queueMicrotask 让出主线程,保证页面可交互。
- 例如:10 万条数据分 100 批,每批 1000 条,拷贝完立即 yield
- 避免递归调用过深,改用栈模拟迭代 + 状态记录,防止栈溢出
- 适合中等规模对象(几 MB 到几十 MB),改造成本低,见效快
移出主线程,交给 Web Worker
百 MB 级 JSON 或含大量嵌套结构的对象,直接在 Worker 中用 structuredClone 处理,主线程只负责发消息和收结果。
- Worker 脚本里接收数据 → 执行 structuredClone → postMessage 返回
- 注意:Worker 无法访问 DOM 和闭包变量,需把依赖打包或通过 importScripts 加载
- 搭配 Workly 等轻量封装库,可近乎零修改迁移拷贝逻辑
绕开拷贝,从源头减少需求
很多场景所谓“必须深拷贝”,其实是防御性编程习惯。与其拷,不如约束可变性。
- 用 Object.freeze 或 immer 的 produce 模式,让原数据不可被意外修改
- 组件传参时,避免用 @Prop 传递整个复杂对象,改用 ID 或 @Builder 按需构造视图
- 状态管理中,优先使用不可变更新(如 Redux Toolkit 的 createReducer),而非手动 clone
选对方法,避开常见陷阱
JSON.parse(JSON.stringify()) 看似简单,但会丢函数、Date、RegExp、undefined、循环引用,且大对象易触发内存峰值甚至崩溃。
- 优先用浏览器原生 structuredClone(支持 Map/Set/Date/RegExp/嵌套对象,也支持循环引用)
- 需兼容老浏览器时,用 Lodash 的 cloneDeep,但记得配合 cloneDeepWith 过滤掉 DOM 节点等不可序列化内容
- 对超大对象,禁用递归实现,改用 BFS 遍历 + WeakMap 记录已访问引用,防循环和栈溢出











