预加载图片在移动端反而变卡了?

夏侯增芳 阅读 58

我在做一个移动端的图片画廊,尝试用 new Image().src = url 预加载下一页的图片,结果发现滑动时反而更卡了,FPS 明显掉。是不是预加载太多导致内存压力大?

目前是进入页面就预加载后面 3 张,代码大概这样:

const preloadImages = (urls) => {
  urls.slice(0, 3).forEach(url => {
    const img = new Image();
    img.src = url;
  });
};

有没有更合适的预加载策略?或者需要配合 IntersectionObserver 延迟加载吗?

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
卿硕
卿硕 Lv1
我之前踩过这个坑。预加载图片听起来是个好主意,但实际上可能会导致性能问题,尤其是在移动端。你提到的FPS下降和内存压力大可能是预加载太多图片导致的。移动端的内存本来就有限,一下子加载太多图片确实会让手机吃不消。

你当前的策略是每次预加载3张图片,这本身没问题,但要考虑一下预加载的时机和条件。可以试试结合 IntersectionObserver 来实现懒加载。这样只有当用户即将看到图片时才开始加载,而不是一上来就把所有可能需要的图片都塞进内存。

下面是一个简单的示例,展示了如何使用 IntersectionObserver 来实现懒加载:

pre class="pure-highlightjs line-numbers">const lazyLoadImages = () => {
const images = document.querySelectorAll('img[data-src]');

const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
observer.unobserve(img);
}
});
}, { threshold: 0.1 });

images.forEach(image => {
imageObserver.observe(image);
});
};

// 在页面加载完成后调用
window.addEventListener('load', lazyLoadImages);


这个方法的好处是,只有当图片进入视口的10%时才会开始加载,这样可以大大减少同时加载的图片数量,提升性能。

另外,确保图片已经经过优化,比如压缩大小和选择合适的格式,这对移动端性能也有很大帮助。有时候,一张图片哪怕只减少几百KB,对移动设备来说都是一个不小的负担。
点赞
2026-03-20 19:11
心虹 Dev
确实,移动端直接预加载3张图很容易翻车。我之前在低端安卓机上踩过类似的坑,内存占用飙升直接导致GC频繁触发。

建议改成懒加载+可视区域预加载组合拳:

const lazyLoader = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
lazyLoader.unobserve(img);

// 预加载下一张(别太多,1张就好)
const next = img.nextElementSibling;
if(next && next.dataset.src) {
const preload = new Image();
preload.src = next.dataset.src;
}
}
});
}, {
rootMargin: '200px' // 提前200px触发
});


几个关键点:
1. 初始用data-src占位,别直接写src
2. 看到当前图片时,才加载它和下一张
3. rootMargin调大点让预加载更顺滑

安全提醒:移动端一定要控制并发数,我见过有人无脑预加载10张图把APP搞崩溃的。还有记得监控内存警告事件,必要时释放资源:

window.addEventListener('memorywarning', () => {
// 干掉非可视区域的图片元素
});


这方案在项目实测过,千元机上也能保持50+ FPS。不过如果你的画廊是横向滑动,可能要把nextElementSibling改成取右侧兄弟节点。
点赞
2026-03-09 12:11