WeakRef 适合图片缓存池,因其不增加引用计数,允许垃圾回收器在无强引用时自动回收图片对象,避免内存泄漏;缓存使用 Map 存储,读取时通过 deref() 判断有效性,天然支持按需失效。

WeakRef 可以让缓存池在不阻止图片对象被垃圾回收的前提下,保留对已解码图片的弱引用。当内存紧张或图片元素被移除 DOM 后,缓存自动失效,无需手动清理。
为什么 WeakRef 适合图片缓存池
传统 Map 缓存(Map<string htmlimageelement></string>)会强持有图片实例,即使对应 <img alt="如何利用 WeakRef 实现一个具备“自动清理”能力的图片懒加载缓存池" > 元素已被卸载、DOM 中无任何引用,图片仍无法被 GC 回收,造成内存泄漏。WeakRef 不增加引用计数,只要图片对象没有其他强引用,就会被自动回收,缓存条目随之“自然消失”。
缓存池核心结构设计
使用 Map<string weakref>></string> 存储 URL 到弱引用的映射;搭配一个辅助的 FinalizationRegistry(可选)用于监听清理时机,但非必需——WeakRef 的核心价值在于“读取时才判断是否有效”,更轻量可靠。
- 缓存键用图片 URL 字符串(注意去参、标准化路径,避免重复缓存同一资源)
- 写入缓存:创建
new Image()→ 设置src→ 等待load→ 存入WeakRef - 读取缓存:调用
weakRef.deref(),返回HTMLImageElement | undefined;若为undefined,说明已被回收,需重新加载
懒加载时的缓存使用流程
在 IntersectionObserver 触发懒加载时,先查缓存;命中则直接赋值给 img.src 或复用其 currentSrc + decode() 提前解码;未命中则发起新请求并缓存结果。
- 避免直接复用已回收的
deref()结果 —— 每次都应检查是否为undefined - 对已缓存的图片,可调用
image.decode()确保解码完成再渲染,提升滚动流畅性 - 不需要定时轮询或监听 DOM 卸载事件来清理缓存,WeakRef 天然支持“按需失效”
一个极简可运行示例
(仅核心逻辑,省略 Observer 和错误处理)
const imageCache = new Map<string, WeakRef<HTMLImageElement>>();
function getCachedImage(src: string): HTMLImageElement | undefined {
const ref = imageCache.get(src);
return ref?.deref();
}
function cacheImage(src: string, img: HTMLImageElement): void {
imageCache.set(src, new WeakRef(img));
}
// 懒加载入口
function loadLazyImage(imgEl: HTMLImageElement) {
const src = imgEl.dataset.src!;
const cached = getCachedImage(src);
if (cached) {
imgEl.src = cached.src;
cached.decode().catch(() => {});
return;
}
const img = new Image();
img.src = src;
img.onload = () => cacheImage(src, img);
imgEl.src = src; // 或用 imgEl.src = img.src 实现零延迟切换
}

















