DEV Community

Addy Osmani
Addy Osmani

Posted on • Edited on • Originally published at addyosmani.com

Speed up next-page navigations with prefetching

What is prefetching?

Loading web pages could be made faster by fetching the next page (or set of resources for the next page) a user is likely to visit ahead of time. We call this prefetching. This can make subsequent navigations appear to load instantly in some cases.

Modern prefetching can be achieved in a number of ways. Most commonly this is done using the browser’s <link rel=prefetch> Resource Hint, which works declaratively via HTML..

<!-- HTML -->
<link rel="prefetch" href="/pages/next-page.html">
<link rel="prefetch" href="/js/chat-widget.js">
Enter fullscreen mode Exit fullscreen mode

or a HTTP Header:

Link: </js/chat-widget.js>; rel=prefetch
Enter fullscreen mode Exit fullscreen mode

Prefetching is supported in Webpack too (see prefetch/preload in Webpack).

<!-- Without prefetching -->
import("ChatWidget");

<!-- With prefetching -->
import(/* webpackPrefetch: true */ "ChatWidget");
Enter fullscreen mode Exit fullscreen mode

Webpack's runtime will inject the correct prefetch statements in the page once the parent chunk has finished loading. In the above case, <link rel="prefetch" href="chat-widget.js">.

Per CanIUse, <link rel=prefetch> has decent cross-browser support.

If a resource in Chrome is prefetched with <link rel=prefetch>, it will be fetched at a low priority and kept around for 5 minutes. This lasts until the resource has been consumed, at which point the normal cache-control rules for the resource will apply.

Unsure what pages on your site may be worth considering prefetching? Check out our experimental helper tool for suggested "top next pages" (based on your analytics):

"Prefetching" can also mostly be accomplished using Service Workers [see prefetching during registration]/fetch() or XHR. Note however, not all of these mechanisms have the same "low priority" fetch behavior as <link rel=prefetch>.

Who is using prefetching today?

Several brands you've probably heard of use prefetching in production:

  • Netflix prefetch JavaScript bundles needed for subsequent navigations ahead of time
  • IndieGogo prefetch Stripe's JavaScript library for credit-card processing on future pages
  • Craigslist prefetch their JS bundle for search results pages
  • Heineken prefetch JS and CSS bundles pages after the date-of-birth verification page may need.

What are the challenges of prefetching?

When a user is on a constrained network connection or a limited data-plan, every last byte counts. While prefetching a number of pages ahead of time can make sense for users on a great WiFi connection, it requires care for those that are not. You don't want to waste anyone's data plan.

You can use the navigator.connection.effectiveType API (part of NetInfo) to only prefetch pages when a user is on a connection that is effectively 4G.

One thing to also be careful about with prefetch is that if requests aren't finished by the time a navigation is initiated, the in-flight prefetch request is cancelled. This can mean wasted bytes so just be sure a user is likely to actually see value from these fetched when using this capability.

Case study

When Japanese publisher Nikkei were confident users would navigate to specific pages, they didn't wait for a navigation to happen.

They leveraged <link rel=prefetch> to prefetch the next page before users tapped on links. Below we can see the impact of waiting for network + server overhead to deliver a page (taking a total of ~880ms). Compare this to prefetching, with almost no request overhead and an immediate page navigation (~37ms).

More on Nikkei can be found in this recent case study.

What is predictive prefetching?

Sites using prefetching typically have a good idea of what top-level pages or resources a user is going to visit and can manually add <link rel=prefetch> tags for them. This manual process can however become harder to achieve for large sites at scale. Once you go several levels deep, it can be difficult to know what the "best" next page is going to be nor how to wire this up without it being a manual process.

Predictive prefetching uses additional data (e.g analytics) to predict what documents users are likely to visit given any URL on a site. This data can then be used to <link rel=prefetch> those pages, improving subsequent page load times. Predictions can be optionally improved using machine learning to ensure only pages with the highest changes of being accessed are fetched ahead of time.

Although there’s nothing here specific to it, Google Analytics has a Reporting API with just enough information to build out predictive prefetching for sites. Minko Gechev, Katie Hempenius and I took advantage of this recently to build a project called Guess.js, which has solutions for 1) predictively prefetching relevant pages and 2) predictively bundling and prefetching the right JavaScript resources that may be needed for those pages (via webpack).

Where can I learn more about predictive prefetching?

Rick Viscomi chatted with Katie Hempenius and I about this topic in depth in case interested in learning more:

We're going to continue exploring opportunities to evolve prefetching on the web. Most recently, we've explored privacy-preserving preserving prefetching using Signed Exchanges, a subset of the emerging web packaging specification.

PS: Keep an eye out for quicklink - a <1KB library I'm releasing that aims to enable faster next-page navigations by prefetching in-viewport links during idle time :)

With thanks to Yoav Weiss for his helpful input on how <link rel=prefetch> works behind the scenes in Chrome

Top comments (9)

Collapse
 
shaijut profile image
Shaiju T • Edited

Hi Interesting Plugin , Thanks :) , Here is another plugin, the author in this and this post compares QuickLink and InstantPage and says that QuickLink doesn't have options like

  • Limit preloads per second .
  • Stops preloading on slow response.
  • Stops preloading if server crashes .

@ben What both of you think which is better ?

Collapse
 
rhymes profile image
rhymes • Edited

Great post Addy,

I starred quicklink the other day and noticed you had a hand in it :D Cool that you're thinking of adding support for preload as well!

I remember that dev.to is using a modified version of InstantClick to make the website feel faster, yours seems a more efficient (thanks to the IntersectionObserver) and modern implementation. Am I correct? Aside from the fact that InstantClick seems not to be maintained anymore.

Collapse
 
andy profile image
Andy Zhao (he/him)

Great overview! I wonder if this is something we (dev.to) would use. Any thoughts @ben ?

Collapse
 
ben profile image
Ben Halpern

Yeah, I'm super into this kind of stuff. We have some workarounds for performance which make it not quite as obvious when and where we'd make use, but I'm super down to pick the right places to start working with this.

I played with prefetch a while back and then kind of let my efforts drop off. I'm super in favor of finding good spots for our use.

Collapse
 
addyosmani profile image
Addy Osmani

Awesome! Love to hear if you end up experimenting with the ideas here more. In case dev.to tries quicklink, we just released a new version that gives you a lot more control over what links/URLs to ignore (RegExp, Array or Function) and what origins you'd like to enable prefetching for too: github.com/GoogleChromeLabs/quickl...

Collapse
 
ahmadawais profile image
Ahmad Awais ⚡️

Been trying out Quicklink. Too little data to share some insights but thanks for that. 👍

Collapse
 
maestromac profile image
Mac Siri

That's super cool. Thanks for sharing!

ps: guessjs.com/ doesn't seem to be working

Collapse
 
addyosmani profile image
Addy Osmani

Thanks! I've updated the link :)

Collapse
 
merrythemes profile image
Merry Themes

Thankful for all the work you do Addy!