Improved prefetching for the photo viewer

TLDR; check out <link rel="prefetch"> if you don't already know about it. It makes prefetching resources really easy.

While flicking through photos in the viewer on this site, ideally you wouldn't need to wait for each photo to load, the next photo should already be fully loaded, even if you jump through a few photos quickly. However, I wasn't achieving this ideal in the viewer I wrote. Frequently the next image wasn't fully loaded in time and you'd see a blurry, partially loaded image or even a blank screen and you'd have to wait a second or two, especially on a slow network. I thought, this is a fairly annoying experience and it distracts user from enjoying the photos.

The first version of the viewer only prefetched one image, so I wanted to make it prefetch many. But, there were some tricky cases to handle. How would I ensure that a prefetch request wasn't canceled midway only to be started again immediately? How would I ensure that prefetching only happened in the background so that it didn't slow down other high priority requests? I worried the solution was going to get complex.

Then I discovered <link rel="prefetch"> which basically solved all the issues better than I could have ever done from Javascript. Instead of writing my writing my own prefetch controls, I just sprinkle a few <link rel="prefetch"> tags into the body and the browser handles all the difficult parts in an intelligent way.

In the end, this is almost all the code I needed to add:

prefetchList(viewerState).map(image => (
  <link rel="prefetch" href={image.url} key={"prefetch-" + image.url} />
))

prefetchList basically just gets the next five images from an array, but there is some slightly more advanced code that tracks the direction the user is browsing ("forward/backward").

So once again, the browser vendors have made my task really simple when I thought it was going to be really complex. Thanks browser vendors!