EN/CH Mode
BRUCE_FE Interview Notes - Page Loading - Deep Dive into Lazy Loading
In-depth analysis of frontend Lazy Loading optimization techniques: image Lazy Loading, component Lazy Loading, and the implementation principles of the IntersectionObserver API, along with a complete analysis of Next.js code splitting technology.
EN/CH Mode

Lazy to read articles? Then watch videos!
Basic Concepts
Lazy Loading is a technique for optimizing web performance, focusing on delaying the loading of non-essential resources (load when visible, wait if not), loading them only when truly needed. This significantly improves initial page load speed, saves resources, and enhances user experience.
Traditional Loading Process:
All resources load simultaneously → Page rendering complete → User can interact
Lazy Loading Process:
Key resources load (load when visible) → Initial page rendering → User can interact → Other resources load as neededIn frontend development, the main application scenarios for Lazy Loading are:
| Application Scenarios | Actual Examples |
|---|---|
| Images and Media Files | Product images on e-commerce sites, video content on social media |
| UI Components and Page Sections | Comment sections at the bottom of pages, pop-up dialogs |
Image Lazy Loading
Traditional Image Loading vs Lazy Loading
Traditional web pages download all <InlineCode><img></InlineCode> tag images at once, regardless of visibility, wasting resources and reducing page load speed.
Traditional Image Loading:
┌──────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ All images
│ │ Image 1 │ │ Image 2 │ │ Image 3 ││ requested at once
│ └──────────┘ └──────────┘ └──────────┘│
│ │◄───────
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ User only
│ │ Image 4 │ │ Image 5 │ │ Image 6 ││ sees here
│ └──────────┘ └──────────┘ └──────────┘│
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ Unseen
│ │ Image 7 │ │ Image 8 │ │ Image 9 ││ also loaded
│ └──────────┘ └──────────┘ └──────────┘│
│ │
└──────────────────────────────────────────┘Lazy Loading only loads images when they are near or enter the viewport, significantly reducing initial page load.
Lazy Loading Images:
┌──────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ Loaded
│ │ Image 1 │ │ Image 2 │ │ Image 3 ││ (in viewport)
│ └──────────┘ └──────────┘ └──────────┘│
│ │◄───────
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ Loading
│ │ Image 4 │ │ Loading...│ │ Loading...││ (near viewport)
│ └──────────┘ └──────────┘ └──────────┘│
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│ Not loaded
│ │ Not loaded│ │ Not loaded│ │ Not loaded││ (far from viewport)
│ └──────────┘ └──────────┘ └──────────┘│
│ │
└──────────────────────────────────────────┘Ways to Implement Image Lazy Loading
1. Native loading='lazy' Attribute
A Lazy Loading attribute supported natively by modern browsers, simple and easy to use, without additional JavaScript.
<img src="image.jpg" loading="lazy" alt=" Lazy Loading 圖片" />2. IntersectionObserver API
A more flexible Lazy Loading method, monitoring whether elements enter the viewport, with good performance.
// Basic Image Lazy Loading Implementation
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; // Load actual image
img.classList.remove('lazy-image');
observer.unobserve(img); // Stop observing after loading
}
});
});
// Observe each lazy loading image
lazyImages.forEach(img => {
imageObserver.observe(img);
});Component Lazy Loading
Skeleton Placeholder Technique
Skeleton is a transitional technique during component loading, displaying an outline before content loads, improving user waiting experience.
Lazy Loading Component Process:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ │ ░░░░░░░░░░░░░░░ │ │ Title Text │
│ │ │ ░░░░░░░░░░░ │ │ Actual Content │
│ Blank Area │ ──► │ ░░░░░░░░░░░░░░░ │ ──► │ Images and Other│
│ (Poor Experience)│ │ ░░░░░░░░░░░ │ │ Interactive Elements│
│ │ │ ░░░░░░░░░░░░░░░ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Initial State Skeleton Placeholder Full Content LoadedGood Skeleton design has the following features:
- 1. Similar structure to actual content
- 2. Use animation effects to indicate 'loading'
- 3. Use appropriate colors, not visually distracting
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>
);
}Deep Understanding of Window.IntersectionObserver API
IntersectionObserver is a great tool for implementing Lazy Loading, as it can monitor the intersection state changes of elements with the viewport.
IntersectionObserver Working Principle:
┌─────────────────────────────────────────┐
│ │
│ Viewport │
│ │
│ ┌─────────────────────────────────┐ │
│ │ │ │
│ │ Visible Area │ │
│ │ │ │
│ └─────────────────────────────────┘ │
│ ▲ │
│ │ │
│ ┌─────────────┐ │ ┌─────────────┐ │
│ │ Element A │ │ │ Element B │ │
│ │ isInter- │ │ │ isInter- │ │
│ │ secting: │ │ │ secting: │ │
│ │ false │ │ │ true │ │
│ └─────────────┘ │ └─────────────┘ │
│ │ │
└───────────────────┼─────────────────────┘
│
Callback triggered on intersection state changeCore Advantages
- 1. Reduces initial page load time
- 2. Reduces server load and saves bandwidth
- 3. Better performance on mobile devices
- 4. Reduces resource waste (users may never scroll to certain content)
// IntersectionObserver Configuration Example
const options = {
root: document.querySelector('#scrollArea'), // Default is viewport
rootMargin: '0px 0px 100px 0px', // Trigger 100px earlier
threshold: [0, 0.5, 1] // Intersection ratio thresholds
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
// Element enters viewport
if (entry.isIntersecting) {
console.log('Element entered viewport, visible ratio: ' + entry.intersectionRatio);
}
});
}, options);
// Start observing element
observer.observe(document.querySelector('#targetElement'));Typical Application Scenarios
- 1. Image/Video Lazy Loading: Load only when elements enter the viewport
- 2. Infinite scrolling: Fetch data from the backend when reaching the bottom, load more content
// Infinite Scroll Example
function createInfiniteScroll(callback) {
// Create observer
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Trigger loading more content
callback();
}
});
}, { rootMargin: '0px 0px 200px 0px' }); // Trigger 200px earlier
// Observe trigger element (usually placed at list bottom)
const trigger = document.querySelector('#loadMoreTrigger');
observer.observe(trigger);
return {
disconnect: () => observer.disconnect()
};
}
// Usage example
const infiniteScroll = createInfiniteScroll(() => {
loadMoreItems(); // Function to load more items
});Best Practices for Lazy Loading
Performance Considerations
- 1. Set a reasonable preloading distance to load content that will soon be visible
- 2. Avoid Lazy Loading too many elements at once
- 3. Provide fallbacks for environments without JavaScript
- 4. Consider network speed differences, provide low-quality previews
<!-- Progressive Lazy Loading -->
<img
src="low-quality-preview.jpg"
data-src="high-quality-image.jpg"
loading="lazy"
class="lazy-image"
alt="Lazy Loading Image"
/>
<noscript>
<!-- Fallback for no JavaScript -->
<img src="high-quality-image.jpg" alt="Lazy Loading Image" />
</noscript>User Experience Optimization
- 1. Avoid page jumps during loading
- 2. Use placeholders to reserve space
- 3. Provide appropriate loading feedback
- 4. Handle fast scrolling situations
/* CSS to prevent page jumps */
.image-container {
position: relative;
aspect-ratio: 16 / 9; /* or use padding-top technique */
background-color: #f0f0f0; /* placeholder color */
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;
}// Smooth display after loading
function onImageLoad(img) {
img.classList.add('loaded');
}
// Using low quality preview technique
function loadHighQualityImage(img) {
const highResImage = new Image();
highResImage.src = img.dataset.src;
highResImage.onload = () => {
img.src = highResImage.src;
onImageLoad(img);
};
}🔥 Common Interview Questions
(1) What is Lazy Loading? What problems does it solve?
Answer:
Lazy Loading is the technique of delaying the loading of resources that are not immediately needed on the page, loading them only when the user truly needs them.
Problems it solves:
- 1. Reduces initial page load time
- 2. Reduces server load and saves bandwidth
- 3. Better performance on mobile devices
- 4. Reduces resource waste (users may never scroll to certain content)
(2) How to handle user experience issues during Lazy Loading?
Answer:
Key points for user experience in Lazy Loading:
Prevent page jumps:
- 1. Set fixed dimensions before image loading
- 2. Use CSS aspect-ratio or padding-top to reserve space
Loading status indication:
- 1. Use Skeleton screens
- 2. Fade in after loading is complete
- 3. Show a blurry preview image first
Handle failure situations:
- 1. Set up a retry mechanism
- 2. Provide friendly error messages
- 3. Prepare backup content
Optimize for special situations:
- 1. Loading priority during fast scrolling
- 2. Preload content that will soon be needed
- 3. Adjust loading strategy based on network speed