惰性加载的核心是推迟非首屏资源加载至用户需要时:原生支持loading="lazy";JS推荐IntersectionObserver监听视口;动态import实现代码分割;需配合占位、加载态与预加载优化体验。

JavaScript 实现惰性加载(Lazy Loading)的核心思路是:**推迟非首屏资源的加载,直到用户真正需要时再触发**。这能显著减少初始页面体积、缩短白屏时间、降低带宽消耗,尤其对图片、视频、组件、路由等资源效果明显。
图片和 iframe 的原生惰性加载
现代浏览器已支持 loading="lazy" 属性,无需 JavaScript 即可实现基础惰性加载:
-
图片:

-
iframe:
注意:该属性在 Chrome 76+、Firefox 75+、Safari 15.4+ 中支持;不支持时会自动降级为正常加载,安全可靠。
使用 IntersectionObserver 监听可视区域
这是最常用、性能最优的 JS 惰性加载方案,比监听 scroll 事件更高效(不触发重排重绘、支持被动监听):
立即学习“Java免费学习笔记(深入)”;
- 创建
IntersectionObserver实例,设定阈值(如{ threshold: 0.1 }表示元素 10% 进入视口即触发) - 遍历所有待懒加载的元素(如
data-src存真实地址的),调用observer.observe(el) - 回调中将
el.dataset.src赋给el.src,并取消监听(避免重复加载)
示例关键代码:
const lazyImages = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver((entries) => {
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 });
lazyImages.forEach(img => observer.observe(img));
动态导入(Dynamic Import)实现代码分割
对 JS 模块或组件做惰性加载,适用于路由切换、弹窗、折叠面板等场景:
- 用
import()(返回 Promise)替代静态import,让模块按需下载执行 - React 中配合
React.lazy()+Suspense加载组件 - Vue 中用
defineAsyncComponent或直接import()返回组件
例如路由级懒加载(Vue Router):
const routes = [
{ path: '/about', component: () => import('./views/About.vue') }
];
结合占位与加载状态提升体验
纯技术懒加载不够,还需优化用户体验:
- 为图片预留宽高或使用骨架屏(Skeleton),防止布局偏移(CLS)
- 添加加载中状态(如淡入动画、loading 图标),避免空白等待
- 预加载关键资源(如首屏图片)可用
,与懒加载互补
不复杂但容易忽略。











