Bypass Lazy Loading for Cached Images

Instantly Loading Cached Images

I recently wrote about Lazy Loading Images with the Intersection Observer API. In that post I showed how to lazily load images when they are within a certain scroll distance. In this post I will discuss how to instantly load images which have been cached when possible to abort the lazy loading behaviour. This prevents the user from seeing the image render when they scroll to it which could be a slightly jarring experience in a Progressive Web App where immediacy is key to the experience.

Accessing the Application Cache

The application caches are defined by WindowOrWorkerGlobalScope.caches which is implemented by Window and WorkerGlobalScope. This means that whereas in a Service Worker's scope the caches are available via self.caches in a regular JavaScript file they are available as window.caches. We can use window.caches in our lazy load script to first check if we have any of the images cached.

The Script

The script involves a few steps:

  • For each image with a data-src attribute which is in the application cache:
    • Load the image.
    • Remove the data-src attribute so the image is no longer marked for lazy loading.
  • Set up all remaining images for lazy loading.

All images stored in the cache are loaded and once complete, lazy loading is set up for any remaining images which were not cached.

For browsers which do not support window.caches all images with the data-src attribute will be lazy loaded as normal.

// Determine the images to be lazy loaded
const lazyImages = document.querySelectorAll('img[data-src]');

// Check for Cache support
if (window.caches) {
  const lazyImages = Array.prototype.slice.call(document.querySelectorAll('img[data-src]'));

  Promise.all(lazyImages.map(img => {
    const src = img.dataset.src;

    // Check if response for this image is cached
    return window.caches.match(src).
    then(response => {
      if (response) {
        // The image is cached - load it
          img.setAttribute('src', src);
          img.setAttribute('alt', img.datasrc.alt);
          img.removeAttribute('data-src');
          img.removeAttribute('data-alt');
      }
    })
  })).
  then(initialiseLazyLoading); // finished loads from cache, lazy load others
} else {
  // cache not supported - lazy load all
  initialiseLazyLoading();
}

function initialiseLazyLoading() {
  // Determine the images to be lazy loaded
  const lazyImages = document.querySelectorAll('img[data-src]');

  // ... set up lazy loading
}

Conclusion

When converting a website into a PWA it is important to think how you can reshape the experience to make more sense in the new format. Lazily loading images you already have cached makes little sense and could make your app's user interface feel laggy. It is not much extra work to load cached images immediately and is an easy win for making the UI more natural.

Tags: JavaScript, PWA