INTRODUCTION
Another way to optimise the First Paint (FP) and First Contentful Paint (FCP) performance metrics of your website is to cache all critical resources after they have been identified.
In this post, I show you how to cache critical resources using service workers.
But first...
WHAT ARE SERVICE WORKERS?
Service workers are scripts that your browser runs in the background, separate from a web page. This opens the door to features that don't need a web page or user interaction.
Today, they already include features like push notifications, background sync and so on.
Service workers allow us to support offline experiences and give us (developers) complete control over such experience.
Before service workers, there was one other API that gave users an offline experience on the web called AppCache. There are a number of issues with the AppCache API that service workers were designed to avoid.
THINGS TO NOTE ABOUT SERVICE WORKERS
- They can't access the DOM directly but instead, service workers can communicate with the pages they control by responding to messages sent to them, and those pages can in turn, manipulate the DOM if needed.
- Service workers are programmable network proxies, allowing you to control how network requests from your page are handled.
- They are terminated when not in use, and restarted when it's next needed.
- Service workers make extensive use of promises.
- Any website implementing a service worker must be served over HTTPS.
LIFECYCLE OF SERVICE WORKERS
A service worker has a lifecycle that is completely separate from your web page.
The first stage in the lifecycle of a service worker is to install it. At this stage, you need to register it, which you do in your page's JavaScript. Registering a service worker will cause the browser to start the service worker install step in the background.
Typically, you cache your critical resources in the install step. If all the files are cached successfully, then the service worker becomes installed. If any of the files fail to download and cache, then the install step will fail and the service worker won't be installed. If the installation fails, the service worker tries again at another time.
After installation, the activation step will follow. This stage is mostly used in handling any management of old caches.
After the activation step, the service worker will control all pages that fall under its scope, though the page that registered the service worker for the first time won't be controlled until it's loaded again.
Once a service worker is in control, it will be in one of two states: either the service worker will be terminated to save memory, or it will handle fetch and message events that occur when a network request or message is made from your page.
BROWSER SUPPORT FOR SERVICE WORKERS
As with all cool features that we may want to use, we have to make sure it is well supported by the various web browsers in an attempt of having a uniform experience for all our users.
Now, let's go into the main content of this post.
USING SERVICE WORKERS TO CACHE CRITICAL RESOURCES
Using service workers to cache critical resources is a relatively easy task to accomplish. To do this, we go through the following steps:
- Register a service worker,
- Install a service worker,
- Returning cache requests.
REGISTERING A SERVICE WORKER
As in the lifecycle of service workers, the first step to caching critical resources is to register your service worker.
if ('serviceWorker' in navigator) { // CHECK IF serviceWorker IS SUPPORTED
window.addEventListener('load', function() {
// REGISTER SERVICE WORKER AFTER PAGE IS LOADED
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// REGISTRATION WAS SUCCESSFUL
console.log('ServiceWorker registration successful with scope: ',registration.scope);
}, function(err) {
// REGISTRATION FAILED
console.log('ServiceWorker registration failed: ', err);
});
});
}
In the code example above, we check if serviceWorker
is supported. If it is, we register a service worker /sw.js
after the page is done loading.
INSTALLING A SERVICE WORKER
After the page controlled by the service worker registers it, we hook into the install
event of the service worker where we cache the critical resources.
var CACHE_NAME = '...'; // CACHE NAME
var urlsToCache = [ // RESOURCES TO CACHE
...
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME) // CREATE A CACHE WITH THE GIVEN NAME
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache); // ADD ALL RESOURCES TO THE CACHE
})
);
});
In the code example above, we perform 4 actions:
- Give our cache a name and specify what resources to cache,
- Listen for the
install
event, - Create a cache with the name
CACHE_NAME
, - Add all resources to the cache.
RETURNING CACHED RESOURCES
Registering and Installing a service worker is not the end of the road as we'll need to return cached resources when a web page makes a network request for the cached resource.
self.addEventListener('fetch', function(event) { // LISTEN FOR NETWORK REQUESTS
event.respondWith( // RESPOND TO NETWORK REQUEST
caches.match(event.request) // CHECK IF RESOURCE EXISTS IN THE CACHE
.then(function(response) {
// Cache hit - return response
if (response) {
return response; // RETURN THE CACHED RESOURCE
}
// MAKE A NETWORK REQUEST FOR THE RESOURCE IF IT CAN'T BE RETRIEVED
// FROM THE CACHE
return fetch(event.request);
}
)
);
});
Here, we listen for any network request from the controlled page, check if the resource exists in the cache, return the cached resource if there is a matching resource in the cache, otherwise, we return the result of a call to fetch
, which will make a network request and return the data if anything can be retrieved from the network.
Top comments (1)
nice read