While optimizations like deferring JavaScript and lazy loading images improve the initial page load by minimizing early resource usage, they can inadvertently cause delays during subsequent user interactions. To strike a balance between saving bandwidth and delivering instant responsiveness, developers can preemptively load resources using three advanced techniques: Prefetching, Prerendering, and Service Worker Precaching.
1. Prefetching
Prefetching hints to the browser that certain resources or pages will likely be needed in the near future, allowing the browser to download them ahead of time during idle periods.
- Resource Prefetching (
<link rel="prefetch">)
Downloads specific assets (like JS, CSS, or images) at the lowest priority. When the user eventually triggers an action needing that asset, it is served instantly from the disk cache.
<head>
<!-- ... -->
<link rel="prefetch" as="script" href="/date-picker.js">
<link rel="prefetch" as="style" href="/date-picker.css">
<!-- ... -->
</head>
The HTML snippet above informs the browser that it can prefetch data-picker.js and data-picker.css once it is idle.
- Browser Support: Works in all modern browsers except Safari (where it is behind a experimental flag).
- Page Prefetching
Downloads an entire HTML document and its subresources (<link rel="prefetch" href="/page" as="document">).
<link rel="prefetch" href="/page" as="document">
- Speculation Rules API
A newer, JSON-based method for Chromium browsers to prefetch pages. Unlike standard prefetching which uses the HTTP cache, speculation rules process and store resources in the memory cache, making retrieval even faster.
- Important Caveats
Avoid prefetching cross-origin documents (due to duplicate request bugs) or highly personalized/authenticated pages (which aren't cached anyway). Tools like Quicklink optimize this by only prefetching links that enter the user's viewport.
2. Prerendering
Prerendering goes a step further than prefetching. Instead of just downloading the page files, the browser fully renders the page and executes its JavaScript in the background. When the user clicks the link, the page is instantly swapped into the foreground.
- Implementation: Handled via the JSON-configured Speculation Rules API.
<script type="speculationrules">
{
"prerender": [
{
"source": "list",
"urls": ["/page-a", "page-b"]
}
]
}
</script>
- Important Caveat: Because prerendering executes JavaScript, it is computationally expensive and memory-intensive. It should be used sparingly and only when you are highly confident the user is about to navigate to that specific page.
- (Note: The older <link rel="prerender"> hint is deprecated in Chrome and now defaults to a "NoState Prefetch", which doesn't execute JS).
3. Service Worker Precaching
This approach leverages a Service Worker to fetch and save static assets into the high-level Cache API (which is controlled by JavaScript and separate from the lower-level HTTP cache).
- How it Works: Precaching occurs during the Service Worker's installation phase. Once cached, assets are served instantly via a "cache-only" strategy, completely bypassing the network during subsequent page navigations.
- Workbox: The article recommends using Google's Workbox library to manage precaching. Workbox utilizes a "precache manifest" (a list of files and version hashes) to automatically handle complex versioning and clean up expired cache entries.
- Use Case Example: On an e-commerce platform, a product listing page can use a service worker to precache the CSS and JS required for the product detail page, providing instantaneous transition speeds.
workbox.precaching.precacheAndRoute([
'/styles/product-page.ac29.css',
'/styles/product-page.39a1.js',
]);
Key Performance Takeaways
- Network & Data Mindfulness: All three techniques consume bandwidth, storage, and CPU. Developers must be conservative, avoiding oversized prefetch manifests.
- User Preferences: Do not trigger these speculative behaviors if the user has enabled the Save-Data signal on their device.
- When in Doubt: Precache/prefetch too little rather than too much, and rely on runtime caching to populate data as the user browses.