虚拟 DOM 本身不直接占用大量内存,真正需回收的是真实 DOM 节点及关联的事件监听器、定时器、数据引用等资源;Vue 中应在 beforeUnmount 钩子中及时销毁第三方插件、清除定时器、解绑事件,确保 DOM 节点被真正移除且无强引用残留,防止内存泄漏和卡顿。

虚拟 DOM 本身不直接占用大量内存,真正需要回收的是它所映射的真实 DOM 节点,以及与之关联的事件监听器、定时器、数据引用等资源。回收是否及时、彻底,直接决定页面是否存在内存泄漏和滚动卡顿。
真实 DOM 节点的销毁是回收的核心
虚拟 DOM 的 diff 算法识别出“被移除”的节点后,框架会调用底层 DOM API(如 remove() 或 removeChild())真正卸载对应的真实节点。这一步必须完成,否则即使 VNode 被丢弃,DOM 元素仍驻留在内存中,持续消耗资源并响应事件。
- Vue 中,removeElementNode() 会递归清理子节点,并移除绑定的事件监听器
- React 使用 unmountComponentAtNode() 或 Fiber 树的 completeWork 阶段触发节点卸载
- 手动操作时,避免只清空 innerHTML —— 它删内容但不销毁节点引用,监听器可能残留
事件与副作用必须同步解绑
一个 DOM 节点若还挂着未清除的事件监听器、定时器、Promise 回调或全局订阅,JavaScript 引擎就无法将其标记为“可回收”,哪怕它早已从视图中消失。
- 在 Vue 的 beforeUnmount(Vue 3)或 beforeDestroy(Vue 2)钩子中清理定时器、取消 axios 请求、解绑 window 事件
- React 函数组件用 useEffect 的清理函数,确保返回的函数执行解绑逻辑
- 避免闭包意外保留对父级作用域的强引用(例如在回调中引用整个组件实例)
虚拟节点(VNode)自身的生命周期管理
VNode 是轻量 JavaScript 对象,本身不需“手动回收”,但它的引用关系会影响垃圾回收效率:
- 旧 VNode 树在新树生成并 patch 完成后,若无外部变量持有,会被 JS 垃圾回收器(标记清除机制)自动回收
- 关键在于避免在 render 函数或 computed 中创建闭包、缓存大对象或重复绑定函数,防止旧 VNode 被意外“悬挂”
- 使用 key 确保节点身份稳定——错误的 key(如用 index)会导致本可复用的节点被销毁重建,徒增回收压力
虚拟列表场景下的定向回收策略
长列表(如 10000 条)启用虚拟滚动时,回收不是“全量清空”,而是按需置换:
- 仅保留在可视区域 + 少量缓冲区(如上下各 5 行)的 DOM 节点,其余立即 remove()
- 滚动过程中,离开视口的节点被销毁,进入视口的新节点被挂载,DOM 总数稳定在 ~100–200 个
- 需配合 requestIdleCallback 或节流滚动监听,避免高频销毁/挂载造成主线程阻塞

















