DEV Community

jbroomer
jbroomer

Posted on

Prefetching Images in JS

Loading...

These are mad times we live in, mad! There is an insatiable demand for a silky smooth user experience, instantaneous loading times, and unlimited content.

When thinking about load times, one thing that comes to mind is images. Have you ever experienced the frustration of being on a loaded webpage, only to have to wait for images to load on further interaction with the page. Of course you have. If you are developing a website with many images you will undoubtedly want to spare your users from this vexation.

Luckily, there is a simple way to go about this if:

  1. You have the image URLs ahead of time
  2. You can accurately predict which images the user will likely see next

If the above isn't true then this article may not be super useful to you.

Basic Prefetching

const urls = [
  "shorturl.at/auLWY",
  "shorturl.at/sBTX5"
];
urls.forEach(imageUrl => {
    const imageElement = new Image(); // Create new image element
    imageElement.onload = () => {}; // Do something on success
    imageElement.onerror = () => {}; // Do something on error
    imageElement.src = imageUrl; // Set the image URL which will trigger a network request
};
Enter fullscreen mode Exit fullscreen mode

Let's talk about why the approach above actually works.

The Image constructor, which is functionally equivalent to document.createElement('img'), creates a new image instance. The purpose of creating these images is not for display, but rather to set the image src attribute which in turn will trigger a network request for the image. If you can accurately predict which images the user is likely to see next based on some logical flow of interaction, then you can ensure the images have already been delivered to the browser by the time the user gets there.

This may seem trivial, but for large scale applications it can save a significant amount of time. In order for this to work effectively, you will need to find a practical place to prefetch in your current environment: before the user sees the images and after any heavy initialization tasks as to not affect your web application's initial load time.

Prefetching w/Promises

const urls = [
  "shorturl.at/auLWY",
  "shorturl.at/sBTX5"
];
Promise.all(urls.map(imageUrl => {
  return new Promise((resolve, reject) => {
    const imageElement = new Image(); // Create new image element
    imageElement.onload = () => { resolve(); }; // Do something on success
    imageElement.onerror = () => { reject(); }; // Do something on error
    imageElement.src = imageUrl; // Set the image URL which will trigger a network request
  };
}))
.then(() => {}) // Do something after all images load
.catch((err)=> {}); // Do something if there are any errors
Enter fullscreen mode Exit fullscreen mode

Additionally, if find it necessary to have more control over the loading state of your images, such as triggering some function when they all load successfully or to conditionally display some skeleton component, there is an easy way to do so using promises.

Simply map each image url to a new promise and resolve/reject the promise as it suits your needs. Wrap the promise array in a Promise.all and use the then and catch methods to execute the appropriate action. That's it!

I hope this article has helped you understand how you can use prefetching to improve your web application's user experience. Let me know in the comments if it works for you!

Top comments (1)

Collapse
 
shadowtime2000 profile image
shadowtime2000

This isn't prefetching, this is lazy loading and I think many browsers support a built in property for this.