文章中英模式
常見的前端面試題目 - 頁面載入 - 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. 根據網速調整加載策略