文章中英模式
常见的前端面试题目 - 页面加载 - Lazy Loading 是什麼?
深入解析前端 Lazy Loading 优化技术:图片 Lazy Loading、组件 Lazy Loading 及 IntersectionObserver API 的原理实现,以及 Next.js 代码分割技术的完整剖析。
文章中英模式

懒得看文章?那就来看视频吧
基本概念
Lazy Loading(懒加载)是优化网页性能的技术,核心是延迟加载非必要资源(有看到才加载,没看到先等等),等到真正需要时才载入。这样能大幅提升页面初始载入速度,省下资源,让用户体验更好。
传统加载流程:
所有资源同时加载 → 页面渲染完成 → 用户可交互
Lazy Loading 流程:
关键资源加载(有看到才加载) → 页面初步渲染 → 用户可交互 → 其他资源按需加载前端开发中,Lazy Loading 主要应用场景:
| 应用场景 | 实际例子 |
|---|---|
| 图片和媒体文件 | 电商网站的产品图片、社交媒体的视频内容 |
| UI 组件和页面区块 | 页面底部的评论区、弹出式对话框 |
图片 Lazy Loading
传统图片加载 vs Lazy Loading
传统网页会一次性下载所有 <InlineCode><img></InlineCode> 标签的图片,无论是否可见,浪费资源且降低页面加载速度。
传统图片加载:
┌──────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ 所有图片
│ │ 图片 1 │ │ 图片 2 │ │ 图片 3 ││ 同时请求
│ └──────────┘ └──────────┘ └──────────┘│
│ │◄───────
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ 用户仅
│ │ 图片 4 │ │ 图片 5 │ │ 图片 6 ││ 看到这里
│ └──────────┘ └──────────┘ └──────────┘│
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ 未显示的
│ │ 图片 7 │ │ 图片 8 │ │ 图片 9 ││ 也被加载
│ └──────────┘ └──────────┘ └──────────┘│
│ │
└──────────────────────────────────────────┘Lazy Loading 只在图片接近或进入视窗时才加载,大幅减少初始页面负载。
Lazy Loading 图片:
┌──────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ 已加载
│ │ 图片 1 │ │ 图片 2 │ │ 图片 3 ││ (在视窗中)
│ └──────────┘ └──────────┘ └──────────┘│
│ │◄───────
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ 正在加载
│ │ 图片 4 │ │ 加载中... │ │ 加载中... ││ (接近视窗)
│ └──────────┘ └──────────┘ └──────────┘│
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ 尚未加载
│ │ 未加载 │ │ 未加载 │ │ 未加载 ││ (远离视窗)
│ └──────────┘ └──────────┘ └──────────┘│
│ │
└──────────────────────────────────────────┘实现图片 Lazy Loading 的方式
1. 原生 loading='lazy' 属性
现代浏览器内建支持的 Lazy Loading 属性,简单易用,无需额外 JavaScript。
<img src="image.jpg" loading="lazy" alt=" Lazy Loading 圖片" />2. IntersectionObserver API
更灵活的 Lazy Loading 方式,监控元素是否进入视窗,性能好。
// 图片 Lazy Loading 基本实现
const lazyImages = document.querySelectorAll('.lazy-image');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // 加载真实图片
img.classList.remove('lazy-image');
observer.unobserve(img); // 加载后停止观察
}
});
});
// 对每个 Lazy Loading 图片进行观察
lazyImages.forEach(img => {
imageObserver.observe(img);
});组件 Lazy Loading
Skeleton 占位符技术
Skeleton(骨架屏)是组件加载中的过渡技术,在内容加载前显示轮廓,让用户等待体验更好。
Lazy Loading 组件流程:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ │ ░░░░░░░░░░░░░░░ │ │ 标题文字 │
│ │ │ ░░░░░░░░░░░ │ │ 实际内容段落 │
│ 空白区域 │ ──► │ ░░░░░░░░░░░░░░░ │ ──► │ 图片和其他 │
│ (不好的体验) │ │ ░░░░░░░░░░░ │ │ 交互元素 │
│ │ │ ░░░░░░░░░░░░░░░ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
初始状态 Skeleton 占位 完整内容加载好的 Skeleton 设计有以下特点:
- 1. 和实际内容有相似的结构
- 2. 用动画效果提示'正在加载'
- 3. 用适当的颜色,不干扰视觉
function CardSkeleton() {
return (
<div className="card-skeleton">
<div className="skeleton-img pulse"></div>
<div className="skeleton-title pulse"></div>
<div className="skeleton-text pulse"></div>
<div className="skeleton-text pulse"></div>
</div>
);
}
function ProductCard({ loading, product }) {
if (loading) {
return <CardSkeleton />;
}
return (
<div className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p>{product.description}</p>
<button>加入購物車</button>
</div>
);
}Window.IntersectionObserver API 深入理解
IntersectionObserver 是实现 Lazy Loading 的好工具,它能监测元素与视窗的交叉状态变化。
IntersectionObserver 工作原理:
┌─────────────────────────────────────────┐
│ │
│ 视口 (Viewport) │
│ │
│ ┌─────────────────────────────────┐ │
│ │ │ │
│ │ 可见区域 (Visible Area) │ │
│ │ │ │
│ └─────────────────────────────────┘ │
│ ▲ │
│ │ │
│ ┌─────────────┐ │ ┌─────────────┐ │
│ │ 元素 A │ │ │ 元素 B │ │
│ │ isInter- │ │ │ isInter- │ │
│ │ secting: │ │ │ secting: │ │
│ │ false │ │ │ true │ │
│ └─────────────┘ │ └─────────────┘ │
│ │ │
└───────────────────┼─────────────────────┘
│
交叉状态变化时触发回调核心优势
- 1. 减少初始页面加载时间
- 2. 降低服务器负担和省流量
- 3. 在手机上性能更好
- 4. 减少资源浪费(用户可能永远不会滚到某些内容)
// IntersectionObserver 配置示例
const options = {
root: document.querySelector('#scrollArea'), // 默认为视窗
rootMargin: '0px 0px 100px 0px', // 提前100px触发
threshold: [0, 0.5, 1] // 交叉比例阈值
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
// 元素进入视窗
if (entry.isIntersecting) {
console.log('元素进入视窗,可见比例: ' + entry.intersectionRatio);
}
});
}, options);
// 开始观察元素
observer.observe(document.querySelector('#targetElement'));典型应用场景
- 1. 图片/视频 Lazy Loading :元素进入视窗才加载
- 2. 无限滚动:到底部就跟后端获取数据,加载更多内容
// 无限滚动示例
function createInfiniteScroll(callback) {
// 创建观察者
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// 触发加载更多内容
callback();
}
});
}, { rootMargin: '0px 0px 200px 0px' }); // 提前200px触发
// 观察触发元素(通常放在列表底部)
const trigger = document.querySelector('#loadMoreTrigger');
observer.observe(trigger);
return {
disconnect: () => observer.disconnect()
};
}
// 使用示例
const infiniteScroll = createInfiniteScroll(() => {
loadMoreItems(); // 加载更多项目的函数
});Lazy Loading 最佳实践
性能考量
- 1. 设定合理预加载距离,提前载入即将看到的内容
- 2. 避免同时 Lazy Loading 太多元素
- 3. 为无 JavaScript 环境提供备选方案
- 4. 考虑网速差异,提供低质量预览
<!-- 渐进式 Lazy Loading -->
<img
src="低质量预览.jpg"
data-src="高质量图片.jpg"
loading="lazy"
class="lazy-image"
alt=" Lazy Loading 图片"
/>
<noscript>
<!-- 无 JavaScript 的备选方案 -->
<img src="高质量图片.jpg" alt=" Lazy Loading 图片" />
</noscript>用户体验优化
- 1. 避免加载时造成页面跳动
- 2. 用占位符保留空间
- 3. 给予适当加载反馈
- 4. 处理快速滚动情况
/* 防止页面跳动的CSS */
.image-container {
position: relative;
aspect-ratio: 16 / 9; /* 或用 padding-top 技巧 */
background-color: #f0f0f0; /* 占位色 */
overflow: hidden;
}
.image-container img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 0.3s ease;
}
.image-container img.loaded {
opacity: 1;
}// 加载完成后平滑显示
function onImageLoad(img) {
img.classList.add('loaded');
}
// 使用低质量预览图技术
function loadHighQualityImage(img) {
const highResImage = new Image();
highResImage.src = img.dataset.src;
highResImage.onload = () => {
img.src = highResImage.src;
onImageLoad(img);
};
}🔥 常见面试题目
(一)什么是 Lazy Loading?它解决了什么问题?
解答:
Lazy Loading 是延迟加载页面中不立即需要的资源,等用户真正需要时才加载。
它解决的问题:
- 1. 减少初始页面加载时间
- 2. 降低服务器负担和省流量
- 3. 在手机上性能更好
- 4. 减少资源浪费(用户可能永远不会滚到某些内容)
(二)如何处理 Lazy Loading 过程中的用户体验问题?
解答:
Lazy Loading 的用户体验关键点:
防止页面跳动:
- 1. 图片加载前先设好固定尺寸
- 2. 用 CSS aspect-ratio 或 padding-top 保留空间
加载状态提示:
- 1. 用 Skeleton 骨架屏
- 2. 加载完成后淡入显示
- 3. 先显示模糊预览图
处理失败情况:
- 1. 设置重试机制
- 2. 提供友好错误提示
- 3. 准备备用内容
特殊情况优化:
- 1. 快速滚动时的加载优先顺序
- 2. 预加载即将需要的内容
- 3. 根据网速调整加载策略