This sample demonstrates basic service worker registration, in conjunction with pre-fetching
of specific resource URLs during the installation phase. Additionally, it illustrates how
window.caches can be used to make calls against the
Cache Storage API
from the context of a normal document. (This was previously only exposed to service workers.)
Live Output
The resources currently in the cache are listed below. Some initial files have been added
via the service worker's install handler. You can add additional files to the cache or
remove files from the context of the current page, without having to pass messages back
and forth to the service worker.
JavaScript Snippet
varCACHE_NAME='window-cache-v1';varcacheEntriesUl=document.querySelector('#cache-entries');functioninitializeUI(){document.querySelector('#files').style.display='block';document.querySelector('#add').addEventListener('click',function(){varurl=document.querySelector('#url').value;if(url){addUrlToCache(url);}});showList();}functionshowList(){// Clear out any previous entries, in case this is being called after adding a// new entry to the cache.while(cacheEntriesUl.firstChild){cacheEntriesUl.removeChild(cacheEntriesUl.firstChild);}// All the Cache Storage API methods return Promises. If you're not familiar// with them, see http://www.html5rocks.com/en/tutorials/es6/promises/// Here, we're iterating over all the available caches, and for each cache,// iterating over all the entries, adding each to the list.window.caches.keys().then(function(cacheNames){cacheNames.forEach(function(cacheName){window.caches.open(cacheName).then(function(cache){returncache.keys();}).then(function(requests){requests.forEach(function(request){addRequestToList(cacheName,request);});});});});}// This uses window.fetch() (https://developers.google.com/web/updates/2015/03/introduction-to-fetch)// to retrieve a Response from the network, and store it in the named cache.// In some cases, cache.add() can be used instead of the fetch()/cache.put(),// but only if we know that the resource we're fetching supports CORS.// cache.add() will fail when the response status isn't 200, and when CORS isn't// supported, the response status is always 0.// (See https://github.com/w3c/ServiceWorker/issues/823).functionaddUrlToCache(url){window.fetch(url,{mode:'no-cors'}).then(function(response){caches.open(CACHE_NAME).then(function(cache){cache.put(url,response).then(showList);});}).catch(function(error){ChromeSamples.setStatus(error);});}// Helper method to add a cached Request to the list of the cache contents.functionaddRequestToList(cacheName,request){varurl=request.url;varspanElement=document.createElement('span');spanElement.textContent=url;varbuttonElement=document.createElement('button');buttonElement.textContent='Remove';buttonElement.dataset.url=url;buttonElement.dataset.cacheName=cacheName;buttonElement.addEventListener('click',function(){remove(this.dataset.cacheName,this.dataset.url).then(function(){varparent=this.parentNode;vargrandParent=parent.parentNode;grandParent.removeChild(parent);}.bind(this));});varliElement=document.createElement('li');liElement.appendChild(spanElement);liElement.appendChild(buttonElement);cacheEntriesUl.appendChild(liElement);}// Given a cache name and URL, removes the cached entry.functionremove(cacheName,url){returnwindow.caches.open(cacheName).then(function(cache){returncache.delete(url);});}if('caches'inwindow){if('serviceWorker'innavigator){navigator.serviceWorker.register('service-worker.js');// As soon as the service worker has been installed, active the UI elements.navigator.serviceWorker.ready.then(initializeUI);}}else{ChromeSamples.setStatus('window.caches is not supported in your browser.');}
Service Worker's JavaScript
/*
Copyright 2015 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/// While overkill for this specific sample in which there is only one cache,// this is one best practice that can be followed in general to keep track of// multiple caches used by a given service worker, and keep them all versioned.// It maps a shorthand identifier for a cache to a specific, versioned cache name.// Note that since global state is discarded in between service worker restarts, these// variables will be reinitialized each time the service worker handles an event, and you// should not attempt to change their values inside an event handler. (Treat them as constants.)// If at any point you want to force pages that use this service worker to start using a fresh// cache, then increment the CACHE_VERSION value. It will kick off the service worker update// flow and the old cache(s) will be purged as part of the activate event handler when the// updated service worker is activated.varCACHE_VERSION=1;varCURRENT_CACHES={prefetch:'window-cache-v'+CACHE_VERSION};self.addEventListener('install',function(event){varurlsToPrefetch=['./static/pre_fetched.txt','./static/pre_fetched.html'];event.waitUntil(caches.open(CURRENT_CACHES.prefetch).then(function(cache){returncache.addAll(urlsToPrefetch).then(function(){console.log('All resources have been fetched and cached.');// skipWaiting() allows this service worker to become active// immediately, bypassing the waiting state, even if there's a previous// version of the service worker already installed.self.skipWaiting();});}).catch(function(error){// This catch() will handle any exceptions from the caches.open()/cache.addAll() steps.console.error('Pre-fetching failed:',error);}));});self.addEventListener('activate',function(event){// clients.claim() tells the active service worker to take immediate// control of all of the clients under its scope.self.clients.claim();// Delete all caches that aren't named in CURRENT_CACHES.// While there is only one cache in this example, the same logic will handle the case where// there are multiple versioned caches.varexpectedCacheNames=Object.keys(CURRENT_CACHES).map(function(key){returnCURRENT_CACHES[key];});event.waitUntil(caches.keys().then(function(cacheNames){returnPromise.all(cacheNames.map(function(cacheName){if(expectedCacheNames.indexOf(cacheName)===-1){// If this cache name isn't present in the array of "expected" cache names,// then delete it.console.log('Deleting out of date cache:',cacheName);returncaches.delete(cacheName);}}));}));});