Lazy Loading 懒加载的实现方式与 Intersection Observer
请解释图片/组件的懒加载(Lazy Loading)实现原理,对比传统 scroll 监听与 Intersection Observer API 的优劣,以及 React.lazy 的工作原理。
回答
编译有声
图片懒加载(Imgage Lazy Loading):
传统 scroll 监听:
window.addEventListener('scroll', () => {
const images = document.querySelectorAll('img[data-src]');
images.forEach(img => {
if (img.getBoundingClientRect().top < window.innerHeight) {
img.src = img.dataset.src;
img.removeAttribute('data-src');
}
});
});
- 缺点:scroll 事件频繁触发(需节流),性能开销大,滚动监听阻塞主线程
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: '200px', // 提前 200px 加载
threshold: 0.01,
});
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
- 异步执行,不阻塞主线程
- 浏览器原生实现,性能优于 scroll 监听
- 支持
rootMargin提前加载
原生属性:<img loading="lazy">(Chrome 76+ 支持)
组件懒加载(React.lazy):
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Spinner />}>
<HeavyComponent />
</Suspense>
);
}
- 底层使用 Webpack 的动态
import()实现代码分割 - 结合路由懒加载(React Router 的
lazy)实现页面级按需加载