2 Copyright 2014 Google Inc. All Rights Reserved.
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 http://www.apache.org/licenses/LICENSE-2.0
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
14 // While overkill for this specific sample in which there is only one cache,
15 // this is one best practice that can be followed in general to keep track of
16 // multiple caches used by a given service worker, and keep them all versioned.
17 // It maps a shorthand identifier for a cache to a specific, versioned cache name.
19 // Note that since global state is discarded in between service worker restarts, these
20 // variables will be reinitialized each time the service worker handles an event, and you
21 // should not attempt to change their values inside an event handler. (Treat them as constants.)
23 // If at any point you want to force pages that use this service worker to start using a fresh
24 // cache, then increment the CACHE_VERSION value. It will kick off the service worker update
25 // flow and the old cache(s) will be purged as part of the activate event handler when the
26 // updated service worker is activated.
28 // commit c7c294d59a9172180cdf14bde9b40ec6c56ce81b
29 // Author: Rob van Son <r.j.j.h.vanson@gmail.com>
30 // Date: Thu May 3 14:03:27 2018 +0200
31 var CACHE_VERSION = 1;
32 var CURRENT_CACHES = {
33 prefetch: 'prefetch-cache-v' + CACHE_VERSION
36 self.addEventListener('install', function(event) {
39 var urlsToPrefetch = [
44 'SpeakGoodChinese3.xml',
45 'SpeakGoodChinese3_Settings.xml',
46 'SpeakGoodChinese3_SelectWords.xml',
47 'SpeakGoodChinese3_Credits.xml',
49 'internationalization_tables.js',
50 'mespeak/mespeak.full.js',
51 'mespeak/mespeak_config.json',
52 'mespeak/voices/zh.json',
54 'fft.js/lib/complex.js',
63 // All of these logging statements should be visible via the "Inspect" interface
64 // for the relevant SW accessed via chrome://serviceworker-internals
65 console.log('Handling install event. Resources to prefetch:', urlsToPrefetch);
68 caches.open(CURRENT_CACHES.prefetch).then(function(cache) {
69 var cachePromises = urlsToPrefetch.map(function(urlToPrefetch) {
70 // This constructs a new URL object using the service worker's script location as the base
72 var url = new URL(urlToPrefetch, location.href);
73 // Append a cache-bust=TIMESTAMP URL parameter to each URL's query string.
74 // This is particularly important when precaching resources that are later used in the
75 // fetch handler as responses directly, without consulting the network (i.e. cache-first).
76 // If we were to get back a response from the HTTP browser cache for this precaching request
77 // then that stale response would be used indefinitely, or at least until the next time
78 // the service worker script changes triggering the install flow.
79 url.search += (url.search ? '&' : '?') + 'cache-bust=' + now;
81 // It's very important to use {mode: 'no-cors'} if there is any chance that
82 // the resources being fetched are served off of a server that doesn't support
83 // CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing).
84 // In this example, www.chromium.org doesn't support CORS, and the fetch()
85 // would fail if the default mode of 'cors' was used for the fetch() request.
86 // The drawback of hardcoding {mode: 'no-cors'} is that the response from all
87 // cross-origin hosts will always be opaque
88 // (https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#cross-origin-resources)
89 // and it is not possible to determine whether an opaque response represents a success or failure
90 // (https://github.com/whatwg/fetch/issues/14).
91 var request = new Request(url, {mode: 'no-cors'});
92 return fetch(request).then(function(response) {
93 if (response.status >= 400) {
94 throw new Error('request for ' + urlToPrefetch +
95 ' failed with status ' + response.statusText);
98 // Use the original URL without the cache-busting parameter as the key for cache.put().
99 return cache.put(urlToPrefetch, response);
100 }).catch(function(error) {
101 console.error('Not caching ' + urlToPrefetch + ' due to ' + error);
105 return Promise.all(cachePromises).then(function() {
106 console.log('Pre-fetching complete.');
108 }).catch(function(error) {
109 console.error('Pre-fetching failed:', error);
114 self.addEventListener('activate', function(event) {
115 // Delete all caches that aren't named in CURRENT_CACHES.
116 // While there is only one cache in this example, the same logic will handle the case where
117 // there are multiple versioned caches.
118 var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
119 return CURRENT_CACHES[key];
123 caches.keys().then(function(cacheNames) {
125 cacheNames.map(function(cacheName) {
126 if (expectedCacheNames.indexOf(cacheName) === -1) {
127 // If this cache name isn't present in the array of "expected" cache names, then delete it.
128 console.log('Deleting out of date cache:', cacheName);
129 return caches.delete(cacheName);
137 self.addEventListener('fetch', function(event) {
138 console.log('Handling fetch event for', event.request.url);
141 // caches.match() will look for a cache entry in all of the caches available to the service worker.
142 // It's an alternative to first opening a specific named cache and then matching on that.
143 caches.match(event.request).then(function(response) {
145 console.log('Found response in cache:', response);
150 console.log('No response found in cache. About to fetch from network...');
152 // event.request will always have the proper mode set ('cors, 'no-cors', etc.) so we don't
153 // have to hardcode 'no-cors' like we do when fetch()ing in the install handler.
154 return fetch(event.request).then(function(response) {
155 console.log('Response from network is:', response);
158 }).catch(function(error) {
159 // This catch() will handle exceptions thrown from the fetch() operation.
160 // Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
161 // It will return a normal response object that has the appropriate error code set.
162 console.error('Fetching failed:', error);