weakset 适合弱引用地记录动画实例以避免内存泄漏,因其只存对象、弱引用、不可遍历,可配合 has() 检测存活状态并自动清理。

WeakSet 本身不能直接“跟踪”生命周期,但它非常适合用来 弱引用地记录正在运行的动画实例,避免内存泄漏,同时让垃圾回收器在动画对象被销毁时自动清理记录。
为什么用 WeakSet 而不是 Set?
动画实例(比如一个自定义的 Animation 类对象)通常生命周期短、数量多,且容易被意外保留引用导致无法回收。WeakSet 的关键特性是:
- 只接受对象作为值,不接受原始值
- 对所存对象是弱引用:只要该对象没有其他强引用,即使还在 WeakSet 中,也会被 GC 回收
- 不可遍历、不能获取大小、不能清空 —— 这反而是优势:你无需手动清理,也不易误操作干扰 GC
典型使用模式:注册 + 检查 + 自动清理
你不需要“监听销毁”,而是通过 WeakSet 的存在性来反映“该实例当前是否仍存活且可能在运行”:
- 启动动画时:将动画实例加入 WeakSet
-
动画帧中(如 requestAnimationFrame 回调):用
weakSet.has(instance)判断它是否还活着;如果返回false,说明已被 GC,应停止对该实例的更新或清理相关资源 - 无需手动删除:对象一离开作用域且无其他引用,WeakSet 自动“失效”该条目
示例代码:
const runningAnimations = new WeakSet();
class SpriteAnimation {
constructor(el) {
this.el = el;
this.isRunning = true;
}
start() {
runningAnimations.add(this); // 弱引用注册
this.tick();
}
tick() {
if (!this.isRunning || !runningAnimations.has(this)) {
// 实例已销毁 或 主动停止 → 安全退出
return;
}
// 执行动画逻辑...
this.el.style.transform = `translateX(${Math.sin(Date.now() / 100)}px)`;
requestAnimationFrame(() => this.tick());
}
stop() {
this.isRunning = false;
}
}
// 使用
const anim = new SpriteAnimation(document.getElementById('box'));
anim.start();
// 后续若 anim = null 或离开作用域,WeakSet 不阻止其回收
配合 cleanup 的增强写法(可选)
如果动画需要显式释放资源(如移除事件监听、取消定时器),可在 tick 中检测到 !runningAnimations.has(this) 后调用清理方法。注意:此时 this 仍可访问(GC 尚未发生,只是标记为可回收),适合做最后清理。
注意事项
- WeakSet 不能用于“主动通知销毁”,它只提供事后检查能力
- 不要依赖
has()返回true表示“一定活跃”——它只表示“尚未被回收”,但对象可能已被逻辑停用(需结合自身状态字段判断) - 若需统计当前活跃数或批量操作,请改用 Map + 弱引用包装(如
WeakMap<instance metadata></instance>),但会增加管理成本
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











