图片懒加载没效果,怎么调整资源加载优先级?

司马广利 阅读 14

大家好,我在做首屏优化时发现图片加载还是卡顿,虽然用了loading="lazy"属性,但页面加载时图片还是阻塞了其他资源。我尝试给图片加了loading="lazy"decoding="async",但效果不明显。

后来改用Intersection Observer手动懒加载,代码大致是这样的:


const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
}, { rootMargin: '0px', threshold: 0.1 });

document.querySelectorAll('img.lazy').forEach(img => observer.observe(img));

但发现部分图片在滚动到视窗外后又重新加载,导致内存飙升。想问问大家怎么合理设置资源加载优先级?特别是图片和关键JS/CSS的加载顺序该怎么协调?

我来解答 赞 2 收藏
二维码
手机扫码查看
2 条解答
东方娇娇
你这个情况主要是懒加载策略和资源优先级没处理好。给你个优化后的方案,复制这个:

const loadImage = (img) => {
return new Promise((resolve, reject) => {
const image = new Image();
image.src = img.dataset.src;
image.onload = () => resolve(image);
image.onerror = reject;
img.src = image.src;
});
};

const observer = new IntersectionObserver(async (entries) => {
entries.forEach(async (entry) => {
if (entry.isIntersecting) {
const img = entry.target;
try {
await loadImage(img);
img.classList.add('loaded');
} catch (error) {
console.error('图片加载失败', img.dataset.src);
}
observer.unobserve(img);
}
});
}, { rootMargin: '50px', threshold: 0.01 });

document.querySelectorAll('img.lazy').forEach(img => {
// 先判断是否在视口内
const rect = img.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom >= 0) {
loadImage(img).then(() => img.classList.add('loaded'));
} else {
observer.observe(img);
}
});

// 提升关键资源加载优先级
document.addEventListener('DOMContentLoaded', () => {
const criticalScripts = document.querySelectorAll('script[data-critical]');
criticalScripts.forEach(script => {
const newScript = document.createElement('script');
newScript.src = script.src;
newScript.async = false;
document.body.appendChild(newScript);
});
});


这里做了几件事:
1 加了个预加载函数loadImage,确保每张图片只加载一次,避免重复加载导致内存飙升
2 调整了IntersectionObserver的参数,rootMargin设置为50px提前加载,threshold调小到0.01提升灵敏度
3 首屏图片直接加载,不走懒加载逻辑
4 关键JS用data-critical标记,页面加载后同步加载这些脚本,确保优先级

记得给图片加个样式:.lazy { opacity: 0; transition: opacity 0.3s; }.lazy.loaded { opacity: 1; },这样加载完会有个淡入效果,体验更好。

对了,别忘了检查你的服务器有没有启用HTTP/2,这玩意对资源并发加载影响挺大。如果还是卡,考虑把大图转成WebP格式,体积能小不少。
点赞 1
2026-02-16 18:02
❤硕辰
❤硕辰 Lv1
这个问题其实挺常见的,图片懒加载确实能优化首屏性能,但如果实现不当或者资源优先级没调好,反而会导致卡顿甚至内存问题。咱们分步骤来解决。

第一步,先确认你的图片懒加载逻辑是不是有问题。你提到部分图片在视窗外重新加载,这很可能是 IntersectionObserver 的配置不合理导致的。特别是 rootMarginthreshold 这两个参数,如果设置得不够严谨,就会导致图片在不该加载的时候被触发加载。我们调整一下配置:


// 优化 IntersectionObserver 配置
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
// 确保只加载一次,避免重复加载
if (!img.src) {
img.src = img.dataset.src;
}
observer.unobserve(img); // 加载完成后停止观察
}
});
}, {
rootMargin: '100px', // 提前加载,避免用户看到空白区域
threshold: 0.01 // 只要图片有一点点进入视口就触发
});

document.querySelectorAll('img.lazy').forEach(img => observer.observe(img));


这里我把 rootMargin 改成了 100px,意思是图片距离视口还有 100 像素的时候就开始加载,这样可以避免用户滚动时看到空白区域。同时把 threshold 设置为 0.01,表示图片只要有一点点进入视口就触发加载,这样更灵敏一些。

第二步,解决图片加载优先级的问题。现代浏览器对资源加载有默认的优先级规则,比如关键的 CSS 和 JS 会被优先加载,而图片通常会被放到低优先级队列中。但如果你手动设置了 src 属性,浏览器可能会重新调整优先级,导致图片抢占了其他资源的加载时间。为了避免这个问题,我们可以使用 fetchpriority 属性来明确指定优先级。比如:


<img data-src="example.jpg" loading="lazy" fetchpriority="low" class="lazy">


这里给图片加上 fetchpriority="low",告诉浏览器这些图片的加载优先级是最低的,不会影响关键资源的加载。

第三步,确保关键的 JS 和 CSS 被优先加载。你可以通过以下方式优化:
1. 把关键的 CSS 内联到 HTML 中,而不是通过外链加载。比如首屏样式直接写到