Quiz

Explain the concept of lazy loading and how it can improve performance

Topics
JavaScriptPerformance

TL;DR

Lazy loading defers non-critical resources until they are likely to be needed, reducing initial network and processing work. Use native loading="lazy" for below-the-fold images and iframes, dynamic import() for optional JavaScript, and IntersectionObserver when custom preloading behavior is required. Do not lazy-load a page's hero or other likely Largest Contentful Paint image; deferring critical content can make performance worse.

<img
src="product-800.jpg"
width="800"
height="600"
loading="lazy"
alt="Blue trail-running shoe" />

The concept of lazy loading and how it can improve performance

What is lazy loading?

Lazy loading is a design pattern used to defer the initialization of an object until the point at which it is needed. This can be applied to various types of resources such as images, videos, scripts, and even data fetched from APIs.

How does lazy loading work?

Lazy loading works by delaying a fetch, initialization, or code evaluation until a trigger such as proximity to the viewport or a user action. It is not automatically beneficial: loading too late can leave blank content as the user scrolls, while splitting JavaScript too aggressively adds request and execution overhead.

Benefits of lazy loading

  • Less initial work: Deferring non-critical resources can reduce initial bytes, parsing, and execution.
  • Reduced bandwidth usage: Resources the user never approaches may never be fetched.
  • Earlier critical-content availability: Competing less for network and main-thread time can help critical content, but verify the effect with loading and field measurements.

Implementing lazy loading

Using the loading attribute in HTML

The simplest way to implement lazy loading for images is by using the loading attribute in HTML.

<img
src="product-800.jpg"
width="800"
height="600"
loading="lazy"
alt="Blue trail-running shoe" />

Using JavaScript

For more complex scenarios, you can use JavaScript to implement lazy loading. Here is an example using the Intersection Observer API:

const lazyImages = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver(
(entries, observer) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
const image = entry.target;
image.src = image.dataset.src;
image.removeAttribute('data-src');
observer.unobserve(image);
}
},
// Start loading shortly before the image enters the viewport.
{ rootMargin: '300px' },
);
for (const image of lazyImages) {
imageObserver.observe(image);
}
// If the whole view is disposed before every image loads:
function cleanup() {
imageObserver.disconnect();
}

The markup must keep a reserved size to avoid layout shifts:

<img
data-src="product-800.jpg"
width="800"
height="600"
alt="Blue trail-running shoe" />

If JavaScript is unavailable, provide a usable fallback when the image is important to understanding the page. Prefer native lazy loading unless you need behavior such as a custom preload distance or support for a different resource type.

Further reading

Exercises

Check your understanding
Beta
Check your understanding Exercise
Check your understanding Exercise

Which lazy-loading decisions are generally appropriate? Select all that apply.