Lazy Loading & Code Splitting
Lazy loading defers loading resources until they're needed — images load when scrolled into view, code splits load on navigation. This dramatically improves initial page load time.
Lazy Loading Strategies
- Image lazy loading — loading='lazy' attribute or Intersection Observer
- Dynamic imports — import('./module') loads code on demand (covered in Module 9)
- Route-based splitting — Load page code only when user navigates to that route
- Component-level splitting — Load heavy components (charts, editors) on demand
- Preloading — <link rel='preload'> for critical resources. Balance: don't preload everything
- Priority hints — fetchpriority='high' for important images, 'low' for below-fold content
Lazy Loading Code
// Native image lazy loading (simplest!)
// <img src="image.jpg" loading="lazy" alt="Description">
// Browser loads image only when near the viewport
// Intersection Observer lazy loading (more control)
function lazyLoadImages() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
// img.src = img.dataset.src;
// img.classList.add("loaded");
console.log("Loaded image:", img.alt || "image");
observer.unobserve(img);
}
});
}, { rootMargin: "200px" }); // start loading 200px before viewport
// document.querySelectorAll("img[data-src]").forEach(img => observer.observe(img));
}
// Dynamic import for heavy features
async function loadEditor() {
console.log("Loading editor...");
// const { Editor } = await import("./heavy-editor.js");
// const editor = new Editor(document.querySelector("#editor"));
console.log("Editor loaded on demand!");
}
// Lazy load on scroll
class LazyLoader {
constructor() {
this.loaded = new Set();
}
async load(resource) {
if (this.loaded.has(resource)) {
console.log(`${resource} already loaded`);
return;
}
console.log(`Loading ${resource}...`);
// await import(resource);
this.loaded.add(resource);
console.log(`${resource} loaded ✅`);
}
}
const loader = new LazyLoader();
loader.load("charts");
loader.load("editor");
loader.load("charts"); // "already loaded"
console.log("Lazy loading reduces initial page load time by 50-80%!");Tip
Tip
Use loading='lazy' on images below the fold as the simplest optimization. For more control, use Intersection Observer. Combine with responsive images (srcset) for additional savings.
ESM is the standard — use import/export for new projects
Common Mistake
Warning
Lazy loading images that are above the fold (visible on page load). This makes the initial view slower, not faster. Only lazy-load images that are below the viewport. Hero images should load eagerly.
Practice Task
Note
Loading optimization: (1) Implement lazy loading for a long image gallery. (2) Add blur-up placeholder technique. (3) Use code splitting to lazy-load a heavy component.
Quick Quiz
Key Takeaways
- Lazy loading defers loading resources until they're needed — images load when scrolled into view, code splits load on navigation.
- Image lazy loading — loading='lazy' attribute or Intersection Observer
- Dynamic imports — import('./module') loads code on demand (covered in Module 9)
- Route-based splitting — Load page code only when user navigates to that route