1- var CACHE_NAME = 'stacktoheap-cache-v2' ;
2- var urlsToCache = [
3- '/' ,
4- '/about/'
5- ] ;
1+ var CACHE_VERSION = 2 ;
2+ var CURRENT_CACHES = {
3+ prefetch : 'stacktoheap-cache-v' + CACHE_VERSION
4+ } ;
65
76self . addEventListener ( 'install' , function ( event ) {
7+ var now = Date . now ( ) ;
8+
9+ var urlsToPrefetch = [
10+ '/' ,
11+ '/about.html'
12+ ] ;
13+
14+ console . log ( 'Handling install event. Resources to prefetch:' , urlsToPrefetch ) ;
15+
816 event . waitUntil (
9- caches . open ( CACHE_NAME )
10- . then ( function ( cache ) {
11- return cache . addAll ( urlsToCache ) ;
12- } )
17+ caches . open ( CURRENT_CACHES . prefetch ) . then ( function ( cache ) {
18+ var cachePromises = urlsToPrefetch . map ( function ( urlToPrefetch ) {
19+ // This constructs a new URL object using the service worker's script location as the base
20+ // for relative URLs.
21+ var url = new URL ( urlToPrefetch , location . href ) ;
22+ // Append a cache-bust=TIMESTAMP URL parameter to each URL's query string.
23+ // This is particularly important when precaching resources that are later used in the
24+ // fetch handler as responses directly, without consulting the network (i.e. cache-first).
25+ // If we were to get back a response from the HTTP browser cache for this precaching request
26+ // then that stale response would be used indefinitely, or at least until the next time
27+ // the service worker script changes triggering the install flow.
28+ url . search += ( url . search ? '&' : '?' ) + 'cache-bust=' + now ;
29+
30+ // It's very important to use {mode: 'no-cors'} if there is any chance that
31+ // the resources being fetched are served off of a server that doesn't support
32+ // CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing).
33+ // In this example, www.chromium.org doesn't support CORS, and the fetch()
34+ // would fail if the default mode of 'cors' was used for the fetch() request.
35+ // The drawback of hardcoding {mode: 'no-cors'} is that the response from all
36+ // cross-origin hosts will always be opaque
37+ // (https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#cross-origin-resources)
38+ // and it is not possible to determine whether an opaque response represents a success or failure
39+ // (https://github.com/whatwg/fetch/issues/14).
40+ var request = new Request ( url , { mode : 'no-cors' } ) ;
41+ return fetch ( request ) . then ( function ( response ) {
42+ if ( response . status >= 400 ) {
43+ throw new Error ( 'request for ' + urlToPrefetch +
44+ ' failed with status ' + response . statusText ) ;
45+ }
46+
47+ // Use the original URL without the cache-busting parameter as the key for cache.put().
48+ return cache . put ( urlToPrefetch , response ) ;
49+ } ) . catch ( function ( error ) {
50+ console . error ( 'Not caching ' + urlToPrefetch + ' due to ' + error ) ;
51+ } ) ;
52+ } ) ;
53+
54+ return Promise . all ( cachePromises ) . then ( function ( ) {
55+ console . log ( 'Pre-fetching complete.' ) ;
56+ } ) ;
57+ } ) . catch ( function ( error ) {
58+ console . error ( 'Pre-fetching failed:' , error ) ;
59+ } )
60+ ) ;
61+ } ) ;
62+
63+ self . addEventListener ( 'activate' , function ( event ) {
64+ // Delete all caches that aren't named in CURRENT_CACHES.
65+ // While there is only one cache in this example, the same logic will handle the case where
66+ // there are multiple versioned caches.
67+ var expectedCacheNames = Object . keys ( CURRENT_CACHES ) . map ( function ( key ) {
68+ return CURRENT_CACHES [ key ] ;
69+ } ) ;
70+
71+ event . waitUntil (
72+ caches . keys ( ) . then ( function ( cacheNames ) {
73+ return Promise . all (
74+ cacheNames . map ( function ( cacheName ) {
75+ if ( expectedCacheNames . indexOf ( cacheName ) === - 1 ) {
76+ // If this cache name isn't present in the array of "expected" cache names, then delete it.
77+ console . log ( 'Deleting out of date cache:' , cacheName ) ;
78+ return caches . delete ( cacheName ) ;
79+ }
80+ } )
81+ ) ;
82+ } )
1383 ) ;
1484} ) ;
1585
1686self . addEventListener ( 'fetch' , function ( event ) {
87+ console . log ( 'Handling fetch event for' , event . request . url ) ;
88+
1789 event . respondWith (
18- caches . match ( event . request )
19- . then ( function ( response ) {
20- if ( response ) {
21- return response ;
22- }
23- return fetch ( event . request ) ;
90+ // caches.match() will look for a cache entry in all of the caches available to the service worker.
91+ // It's an alternative to first opening a specific named cache and then matching on that.
92+ caches . match ( event . request ) . then ( function ( response ) {
93+ if ( response ) {
94+ console . log ( 'Found response in cache:' , response ) ;
95+
96+ return response ;
2497 }
25- )
98+
99+ console . log ( 'No response found in cache. About to fetch from network...' ) ;
100+
101+ // event.request will always have the proper mode set ('cors, 'no-cors', etc.) so we don't
102+ // have to hardcode 'no-cors' like we do when fetch()ing in the install handler.
103+ return fetch ( event . request ) . then ( function ( response ) {
104+ console . log ( 'Response from network is:' , response ) ;
105+
106+ return response ;
107+ } ) . catch ( function ( error ) {
108+ // This catch() will handle exceptions thrown from the fetch() operation.
109+ // Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
110+ // It will return a normal response object that has the appropriate error code set.
111+ console . error ( 'Fetching failed:' , error ) ;
112+
113+ throw error ;
114+ } ) ;
115+ } )
26116 ) ;
27117} ) ;
0 commit comments