Problem Statement
What is lazy loading in JavaScript?
Explanation
Lazy loading defers loading of resources like images, scripts, or modules until they are actually needed.
It improves initial page load time by loading only critical resources first. Non-critical resources load on demand.
Common applications include images in viewport, code splitting, infinite scroll, and modal content.
Modern browsers support native lazy loading for images with the loading attribute.
JavaScript dynamic imports enable lazy loading of modules.
Understanding lazy loading is crucial for building performant web applications.
Code Solution
SolutionRead Only
// NATIVE IMAGE LAZY LOADING
// Modern browsers support loading="lazy"
// <img src="image.jpg" loading="lazy" alt="Description">
// INTERSECTION OBSERVER API
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // Load actual image
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
// HTML:
// <img data-src="actual-image.jpg" src="placeholder.jpg" alt="">
// DYNAMIC MODULE IMPORT
// Load module only when needed
button.addEventListener('click', async () => {
const module = await import('./heavy-module.js');
module.init();
});
// Lazy load component
async function loadComponent() {
const {default: Component} = await import('./Component.js');
const component = new Component();
component.render();
}
// LAZY LOAD SCRIPTS
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.body.appendChild(script);
});
}
// Load only when needed
button.addEventListener('click', async () => {
await loadScript('https://cdn.example.com/library.js');
// Use library
});
// LAZY LOAD CSS
function loadCSS(href) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
// Load styles for specific feature
if (userWantsFeature) {
loadCSS('/styles/feature.css');
}
// INFINITE SCROLL WITH LAZY LOADING
let page = 1;
let loading = false;
const loadMoreContent = async () => {
if (loading) return;
loading = true;
const data = await fetch(`/api/items?page=${page}`);
const items = await data.json();
items.forEach(item => {
container.appendChild(createItemElement(item));
});
page++;
loading = false;
};
window.addEventListener('scroll', throttle(() => {
const scrollPosition = window.scrollY + window.innerHeight;
const threshold = document.body.scrollHeight - 500;
if (scrollPosition >= threshold) {
loadMoreContent();
}
}, 200));
// LAZY LOAD MODAL CONTENT
let modalContent = null;
button.addEventListener('click', async () => {
if (!modalContent) {
// Load only on first open
modalContent = await fetch('/modal-content.html');
}
modal.innerHTML = modalContent;
modal.style.display = 'block';
});
// CODE SPLITTING WITH WEBPACK
// Webpack automatically splits this into separate chunk
import(/* webpackChunkName: "chart" */ './chart.js')
.then(module => {
const chart = new module.Chart();
chart.render();
});
// LAZY LOADING FUNCTIONS
class LazyLoader {
constructor() {
this.cache = {};
}
async load(name, loader) {
if (this.cache[name]) {
return this.cache[name];
}
const result = await loader();
this.cache[name] = result;
return result;
}
}
const loader = new LazyLoader();
// Load only when needed
const chart = await loader.load('chart', () =>
import('./chart.js')
);
// PRACTICAL PATTERNS
// Lazy load on hover (prefetch)
link.addEventListener('mouseenter', () => {
// Start loading before click
import('./page.js');
}, {once: true});
// Lazy load on idle
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
import('./analytics.js');
});
}
// Lazy load fonts
const font = new FontFace(
'MyFont',
'url(/fonts/myfont.woff2)'
);
// Load only when needed
button.addEventListener('click', async () => {
await font.load();
document.fonts.add(font);
document.body.style.fontFamily = 'MyFont';
});
// LAZY LOADING WITH WEBPACK
// Automatically code-splits
const heavyFeature = () => import('./heavy-feature');
if (condition) {
heavyFeature().then(module => {
module.init();
});
}
// BENEFITS
// - Faster initial page load
// - Reduced bandwidth usage
// - Better user experience
// - Lower server costs
// - Improved performance metrics