weakmap 通过弱引用键防止内存泄漏,从而间接降低内存溢出风险;其键必须为对象且不阻止 gc,适用于 dom 元素等元数据缓存,但不解决 value 大对象回收问题。

闭包在函数缓存(如 memoization)中非常实用,但若不加约束,容易把大量数据长期保留在内存中。关键不是禁用闭包,而是让缓存有边界、可淘汰、不拖累 DOM 或大对象。
限制缓存容量并启用 LRU 淘汰机制
无上限的 Map 或 Object 缓存会持续增长,尤其当参数组合多、值本身较大时。应主动控制缓存大小:
- 用固定长度的数组或 Map 实现最近最少使用(LRU)策略,超出容量时删除最久未用项
- 避免直接缓存整个响应对象,只缓存必要字段(如 id + status),而非原始 API 返回的完整 data 树
- 对参数做归一化处理(如 JSON.stringify 排序后的键值对),防止相同逻辑因参数顺序不同生成多个缓存项
避免缓存中持有 DOM 元素或大型数据结构
闭包缓存函数若内部引用了 document.querySelector 结果或 new ArrayBuffer(10MB),这些对象将无法被回收:
- 缓存键值应为原始类型(字符串、数字)或轻量对象(如 { id: 123 }),禁止传入 element、window、大型数组等
- 若必须关联 DOM 状态,改用 WeakMap:它以元素为键,不阻止元素被移除后自动清理对应缓存
- 缓存值为对象时,优先用结构化克隆(structuredClone)提取子集,而不是直接赋值引用
为缓存设置显式生命周期和清理入口
很多缓存工具缺少销毁能力,导致模块卸载后缓存仍驻留。需提供主动释放通道:
- 返回带 clear() 方法的缓存函数,例如 const memoFn = memoize(fn); memoFn.clear()
- 在组件 unmount、路由离开或定时器到期时调用清理,不要依赖“自然消失”
- 对长期运行的缓存(如全局配置解析器),增加过期时间(TTL),通过 setTimeout 定期清空过期项
用弱引用替代强映射关系
当缓存需绑定到易销毁对象(如临时创建的 canvas、表单项 DOM)时,普通 Map 会造成泄漏:
- 改用 WeakMap 存储 DOM → 计算结果 映射,节点被 remove 后,对应缓存条目自动失效
- ES2023+ 可结合 WeakRef 包装缓存值,在读取前检查是否 still alive,避免访问已释放内存
- 禁用 window.cache = new Map() 这类全局强引用缓存,改用模块级 const cache = new Map() 并配合 export { clearCache }
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











