├── .gitattributes ├── README.md ├── chapter02.js ├── chapter03.js ├── chapter04.js ├── chapter05.js ├── chapter06.js ├── chapter07.js └── chapter08.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | Here's the code used in the book [Going Offline](https://abookapart.com/products/going-offline): 4 | 5 | * [chapter02.js](chapter02.js) 6 | * [chapter03.js](chapter03.js) 7 | * [chapter04.js](chapter04.js) 8 | * [chapter05.js](chapter05.js) 9 | * [chapter06.js](chapter06.js) 10 | * [chapter07.js](chapter07.js) 11 | * [chapter08.js](chapter08.js) 12 | 13 | The [code for chapter 7](chapter07.js) is updated to fix [this error](https://adactio.com/journal/14086). 14 | -------------------------------------------------------------------------------- /chapter02.js: -------------------------------------------------------------------------------- 1 | if (navigator.serviceWorker) { 2 | // Your code goes here. 3 | } 4 | 5 | if ('serviceWorker' in navigator) { 6 | // Your code goes here. 7 | } 8 | 9 | if (navigator.serviceWorker !== undefined) { 10 | // Your code goes here. 11 | } 12 | 13 | navigator.serviceWorker.register('/myapp/serviceworker1.js'); 14 | navigator.serviceWorker.register('/myotherapp/serviceworker2.js'); 15 | 16 | navigator.serviceWorker.register('/serviceworker1.js'); 17 | navigator.serviceWorker.register('/myapp/serviceworker2.js'); 18 | 19 | navigator.serviceWorker.register('/serviceworker2.js', { 20 | scope: '/myapp/' 21 | }); 22 | 23 | if (navigator.serviceWorker) { 24 | navigator.serviceWorker.register('/serviceworker.js'); 25 | } 26 | 27 | promise 28 | .then( function () { 29 | // Yay! It worked. 30 | }); 31 | 32 | promise 33 | .then( function () { 34 | // Yay! It worked. 35 | }) 36 | .catch( function () { 37 | // Boo! It failed. 38 | }); 39 | 40 | promise.then( 41 | function () { 42 | // Yay! It worked. 43 | } 44 | ).catch( 45 | function () { 46 | // Boo! It failed. 47 | } 48 | ); 49 | 50 | promise 51 | .then(doSomething) 52 | .catch(doSomethingElse); 53 | 54 | 55 | if (navigator.serviceWorker) { 56 | navigator.serviceWorker.register('/serviceworker.js') 57 | .then( function () { 58 | console.log('Success!'); 59 | }) 60 | .catch( function () { 61 | console.error('Failure!'); 62 | }); 63 | console.log('All done.'); 64 | } 65 | 66 | navigator.serviceWorker.register('/serviceworker.js') 67 | .then( function (registration) { 68 | console.log('success!', registration.scope); 69 | }); 70 | 71 | navigator.serviceWorker.register('/serviceworker.js') 72 | .then( function (x) { 73 | console.log('success!', x.scope); 74 | }); 75 | 76 | navigator.serviceWorker.register('/nothing.js') 77 | .catch( function (error) { 78 | console.log('Failure!', error); 79 | }); 80 | 81 | navigator.serviceWorker.register('/nothing.js') 82 | .catch( function (y) { 83 | console.error('Failure!', y); 84 | }); 85 | 86 | if (navigator.serviceWorker) { 87 | navigator.serviceWorker.register('/serviceworker.js') 88 | .then( function (registration) { 89 | console.log('Success!', registration.scope); 90 | }) 91 | .catch( function (error) { 92 | console.error('Failure!', error); 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /chapter03.js: -------------------------------------------------------------------------------- 1 | addEventListener('fetch', function (event) { 2 | console.log('The service worker is listening.'); 3 | }); 4 | 5 | addEventListener('install', function (event) { 6 | console.log('The service worker is installing . . . '); 7 | }); 8 | 9 | addEventListener('activate', function (event) { 10 | console.log('The service worker is activated.'); 11 | }); 12 | 13 | addEventListener('fetch', function (event) { 14 | // Do something with 'event' data. 15 | }); 16 | 17 | addEventListener('fetch', function (z) { 18 | // Do something with 'z' data. 19 | }); 20 | 21 | addEventListener('fetch', function (fetchEvent) { 22 | // Do something with 'fetchEvent' data. 23 | }); 24 | 25 | addEventListener('fetch', fetchEvent => { 26 | // Do something with 'fetchEvent' data. 27 | }); 28 | 29 | addEventListener('fetch', fetchEvent => { 30 | var request = fetchEvent.request; 31 | }); 32 | 33 | addEventListener('fetch', fetchEvent => { 34 | const request = fetchEvent.request; 35 | }); 36 | 37 | addEventListener('fetch', fetchEvent => { 38 | const request = fetchEvent.request; 39 | console.log(request); 40 | }); 41 | 42 | addEventListener('fetch', fetchEvent => { 43 | fetchEvent.respondWith( 44 | new Response('Hello, world!') 45 | ); // end respondWith 46 | }); // end addEventListener 47 | 48 | fetch(request) 49 | .then( responseFromFetch => { 50 | // Success! 51 | }) 52 | .catch( error => { 53 | // Failure! 54 | }); 55 | 56 | addEventListener('fetch', fetchEvent => { 57 | const request = fetchEvent.request; 58 | fetchEvent.respondWith( 59 | fetch(request) 60 | .then( responseFromFetch => { 61 | return responseFromFetch; 62 | }) // end fetch then 63 | ); // end respondWith 64 | }); // end addEventListener 65 | 66 | addEventListener('fetch', fetchEvent => { 67 | const request = fetchEvent.request; 68 | fetchEvent.respondWith( 69 | fetch(request) 70 | .then(responseFromFetch => { 71 | return responseFromFetch; 72 | }) // end fetch then 73 | .catch(error => { 74 | return new Response('Oops! Something went wrong.'); 75 | }) // end fetch catch 76 | ); // end respondWith 77 | }); // end addEventListener 78 | 79 | return new Response('
Something went wrong.
'); 80 | 81 | return new Response( 82 | 'Something went wrong.
', 83 | { 84 | headers: {'Content-type': 'text/html; charset=utf-8'} 85 | } 86 | ); 87 | -------------------------------------------------------------------------------- /chapter04.js: -------------------------------------------------------------------------------- 1 | const staticCacheName = 'staticfiles'; 2 | 3 | addEventListener('install', installEvent => { 4 | // install-handling code goes here 5 | }); 6 | 7 | addEventListener('fetch', fetchEvent => { 8 | // fetch-handling code goes here 9 | }); 10 | 11 | addEventListener('install', installEvent => { 12 | installEvent.waitUntil( 13 | // Cache your files here 14 | ); // end waitUntil 15 | }); // end addEventListener 16 | 17 | caches.open(staticCacheName) 18 | .then( cache => { 19 | // Success! 20 | }) 21 | .catch( error => { 22 | // Failure! 23 | }); 24 | 25 | addEventListener('install', installEvent => { 26 | installEvent.waitUntil( 27 | caches.open(staticCacheName) 28 | .then( staticCache => { 29 | // Cache your files here 30 | }) // end open then 31 | ); // end waitUntil 32 | }); // end addEventListener 33 | 34 | staticCache.addAll([ 35 | '/path/to/stylesheet.css', 36 | '/path/to/javascript.js', 37 | '/path/to/font.woff', 38 | '/path/to/icon.svg' 39 | ]); 40 | 41 | addEventListener('install', installEvent => { 42 | installEvent.waitUntil( 43 | caches.open(staticCacheName) 44 | .then( staticCache => { 45 | return staticCache.addAll([ 46 | '/path/to/stylesheet.css', 47 | '/path/to/javascript.js', 48 | '/path/to/font.woff', 49 | '/path/to/icon.svg' 50 | ]); // end return addAll 51 | }) // end open then 52 | ); // end waitUntil 53 | }); // end addEventListener 54 | 55 | addEventListener('install', installEvent => { 56 | installEvent.waitUntil( 57 | caches.open(staticCacheName) 58 | .then( staticCache => { 59 | // nice to have 60 | staticCache.addAll([ 61 | '/path/to/font.woff', 62 | '/path/to/icon.svg' 63 | ]); // end addAll 64 | // must have 65 | return staticCache.addAll([ 66 | '/path/to/stylesheet.css', 67 | '/path/to/javascript.js' 68 | ]); // end return addAll 69 | }) // end open then 70 | ); // end waitUntil 71 | }); // end addEventListener 72 | 73 | addEventListener('fetch', fetchEvent => { 74 | const request = fetchEvent.request; 75 | fetchEvent.respondWith( 76 | // fetch-handling code goes here 77 | ); // end respondWith 78 | }); // end addEventListener 79 | 80 | caches.open(staticCacheName) 81 | .then( staticCache => { 82 | return staticCache.match(request); 83 | }); 84 | 85 | caches.match(request); 86 | 87 | caches.match(request) 88 | .then( responseFromCache => { 89 | // Success! 90 | }) 91 | .catch( error => { 92 | // Failure! 93 | }); 94 | 95 | addEventListener('fetch', fetchEvent => { 96 | const request = fetchEvent.request; 97 | fetchEvent.respondWith( 98 | caches.match(request) 99 | .then( responseFromCache => { 100 | if (responseFromCache) { 101 | return responseFromCache; 102 | } // end if 103 | }) // end match then 104 | ); // end respondWith 105 | }); // end addEventListener 106 | 107 | return fetch(request) 108 | .then( responseFromFetch => { 109 | return responseFromFetch; 110 | }); 111 | 112 | return fetch(request); 113 | 114 | if (responseFromCache) { 115 | return responseFromCache; 116 | } else { 117 | return fetch(request); 118 | } 119 | 120 | if (responseFromCache) { 121 | return responseFromCache; 122 | } 123 | return fetch(request); 124 | 125 | return responseFromCache || fetch(request); 126 | 127 | addEventListener('fetch', fetchEvent => { 128 | const request = fetchEvent.request; 129 | fetchEvent.respondWith( 130 | // First, look in the cache. 131 | caches.match(request) 132 | .then( responseFromCache => { 133 | if (responseFromCache) { 134 | return responseFromCache; 135 | } // end if 136 | // Otherwise fetch from the network. 137 | return fetch(request); 138 | }) // end match then 139 | ); // end respondWith 140 | }); // end addEventListener 141 | 142 | const staticCacheName = 'staticfiles'; 143 | 144 | const version = 'V0.01'; 145 | 146 | const version = 'V0.01'; 147 | const staticCacheName = version + 'staticfiles'; 148 | 149 | const version = 'V0.02'; 150 | 151 | return staticCache.addAll([ 152 | '/path/to/stylesheet-v2.css', 153 | '/path/to/javascript-v3.js' 154 | ]); 155 | 156 | addEventListener('install', installEvent => { 157 | installEvent.waitUntil( 158 | // Cache your files here 159 | ); // end waitUntil 160 | }); // end addEventListener 161 | 162 | addEventListener('install', installEvent => { 163 | skipWaiting(); 164 | installEvent.waitUntil( 165 | // Cache your files here 166 | ); // end waitUntil 167 | }); // end addEventListener 168 | 169 | const version = 'V0.03'; 170 | 171 | const staticCacheName = version + 'staticfiles'; 172 | 173 | addEventListener('activate', activateEvent => { 174 | activateEvent.waitUntil( 175 | // Clean all the things! 176 | ); // end waitUntil 177 | }); // end addEventListener 178 | 179 | caches.keys() 180 | .then( cacheNames => { 181 | // loop through the cacheNames array 182 | }) 183 | 184 | caches.keys() 185 | .then( cacheNames => { 186 | return Promise.all( 187 | // asynchronous code goes here 188 | ); 189 | }) 190 | 191 | cacheNames.map( cacheName => { 192 | if (cacheName != staticCacheName) { 193 | // this cacheName needs to go! 194 | } 195 | }); 196 | 197 | if (cacheName != staticCacheName) { 198 | return caches.delete(cacheName); 199 | } 200 | 201 | addEventListener('activate', activateEvent => { 202 | activateEvent.waitUntil( 203 | caches.keys() 204 | .then( cacheNames => { 205 | return Promise.all( 206 | cacheNames.map( cacheName => { 207 | if (cacheName != staticCacheName) { 208 | return caches.delete(cacheName); 209 | } // end if 210 | }) // end map 211 | ); // end return Promise.all 212 | }) // end keys then 213 | .then( () => { 214 | return clients.claim(); 215 | }) // end then 216 | ); // end waitUntil 217 | }); // end addEventListener 218 | 219 | 220 | addEventListener('install', installEvent => { 221 | // Cache some files. 222 | }); 223 | addEventListener('activate', activateEvent => { 224 | // Clean up old caches. 225 | }); 226 | -------------------------------------------------------------------------------- /chapter05.js: -------------------------------------------------------------------------------- 1 | const version = 'V0.04'; 2 | const staticCacheName = version + 'staticfiles'; 3 | addEventListener('install', installEvent => { 4 | installEvent.waitUntil( 5 | caches.open(staticCacheName) 6 | .then( staticCache => { 7 | // these files don’t block installation 8 | staticCache.addAll([ 9 | '/path/to/font.woff', 10 | '/path/to/icon.svg' 11 | ]); // end addAll 12 | // these files must be cached for installation 13 | return staticCache.addAll([ 14 | '/path/to/stylesheet.css', 15 | '/path/to/javascript.js', 16 | '/offline.html' 17 | ]); // end return addAll 18 | }) // end open then 19 | ); // end waitUntil 20 | }); // end addEventListener 21 | 22 | return fetch(request); 23 | 24 | return fetch(request) 25 | .catch( error => { 26 | // Serve up a fallback. 27 | }); 28 | 29 | return fetch(request) 30 | .catch( error => { 31 | return caches.match('/offline.html'); 32 | }); 33 | 34 | addEventListener('fetch', fetchEvent => { 35 | const request = fetchEvent.request; 36 | fetchEvent.respondWith( 37 | // First, look in the cache. 38 | caches.match(request) 39 | .then( responseFromCache => { 40 | if (responseFromCache) { 41 | return responseFromCache; 42 | } // end if 43 | // Otherwise fetch from the network. 44 | return fetch(request) 45 | .catch( error => { 46 | // Show a fallback page instead 47 | return caches.match('/offline.html'); 48 | }); // end fetch catch + return 49 | }) // end match then 50 | ); // end respondWith 51 | }); // end addEventListener 52 | 53 | if (request.headers.get('Accept').includes('text/html')) { 54 | // true! 55 | } else { 56 | // false! 57 | } 58 | 59 | addEventListener('fetch', fetchEvent => { 60 | const request = fetchEvent.request; 61 | if (request.headers.get('Accept').includes('text/html')) { 62 | // HTML-handling logic goes here. 63 | } else if (request.headers.get('Accept').includes('image')) { 64 | // Image-handling logic goes here. 65 | } else { 66 | // Logic for everything else goes here. 67 | } 68 | }); 69 | 70 | addEventListener('fetch', fetchEvent => { 71 | const request = fetchEvent.request; 72 | if (request.headers.get('Accept').includes('text/html')) { 73 | // HTML-handling logic goes here. 74 | return; // go no further 75 | } 76 | if (request.headers.get('Accept').includes('image')) { 77 | // Image-handling logic goes here. 78 | return; // go no further 79 | } 80 | // Logic for everything else goes here. 81 | }); 82 | 83 | const version = 'V0.04'; 84 | const staticCacheName = version + 'staticfiles'; 85 | const imageCacheName = 'images'; 86 | 87 | const cacheList = [ 88 | staticCacheName, 89 | imageCacheName 90 | ]; 91 | 92 | if (cacheName != staticCacheName) { 93 | return caches.delete(cacheName); 94 | } 95 | 96 | if (!cacheList.includes(cacheName)) { 97 | return caches.delete(cacheName); 98 | } 99 | 100 | addEventListener('activate', activateEvent => { 101 | activateEvent.waitUntil( 102 | caches.keys() 103 | .then( cacheNames => { 104 | return Promise.all( 105 | cacheNames.map( cacheName => { 106 | if (!cacheList.includes(cacheName)) { 107 | return caches.delete(cacheName); 108 | } // end if 109 | }) // end map 110 | ); // end return Promise.all 111 | }) // end keys then 112 | .then( () => { 113 | return clients.claim(); 114 | }) // end then 115 | ); // end waitUntil 116 | }); // end addEventListener 117 | 118 | // When the user requests an HTML file . . . 119 | if (request.headers.get('Accept').includes('text/html')) { 120 | fetchEvent.respondWith( 121 | // fetch that page from the network 122 | fetch(request) 123 | .catch( error => { 124 | // otherwise show the fallback page. 125 | return caches.match('/offline.html'); 126 | }) // end fetch catch 127 | ); // end respondWith 128 | return; // go no further 129 | } // end if 130 | 131 | // When the user requests an image . . . 132 | if (request.headers.get('Accept').includes('image')) { 133 | fetchEvent.respondWith( 134 | // look for a cached copy of the image 135 | caches.match(request) 136 | .then( responseFromCache => { 137 | if (responseFromCache) { 138 | return responseFromCache; 139 | } // end if 140 | // otherwise fetch the image from the network 141 | return fetch(request) 142 | .then( responseFromFetch => { 143 | // and put a copy in the cache. 144 | const copy = responseFromFetch.clone(); 145 | fetchEvent.waitUntil( 146 | caches.open(imageCacheName) 147 | .then( imageCache => { 148 | return imageCache.put(request, copy); 149 | }) // end open then 150 | ); // end waitUntil 151 | return responseFromFetch; 152 | }); // end fetch then + return 153 | }) // end match then 154 | ); // end respondWith 155 | return; // go no further 156 | } // end if 157 | 158 | // For everything else . . . 159 | fetchEvent.respondWith( 160 | // look for a cached copy of the file 161 | caches.match(request) 162 | .then( responseFromCache => { 163 | if (responseFromCache) { 164 | return responseFromCache; 165 | } // end if 166 | // otherwise fetch from the network. 167 | return fetch(request); 168 | }); // end match then 169 | ); // end respondWith 170 | 171 | addEventListener('fetch', fetchEvent => { 172 | const request = fetchEvent.request; 173 | // When the user requests an HTML file . . . 174 | if (request.headers.get('Accept').includes('text/html')) { 175 | fetchEvent.respondWith( 176 | // fetch that page from the network 177 | fetch(request) 178 | .catch( error => { 179 | // otherwise show the fallback page. 180 | return caches.match('/offline.html'); 181 | }) // end fetch catch 182 | ); // end respondWith 183 | return; // go no further 184 | } // end if 185 | // When the user requests an image . . . 186 | if (request.headers.get('Accept').includes('image')) { 187 | fetchEvent.respondWith( 188 | // look for a cached version of the image 189 | caches.match(request) 190 | .then( responseFromCache => { 191 | if (responseFromCache) { 192 | return responseFromCache; 193 | } // end if 194 | // otherwise fetch the image from the network 195 | return fetch(request) 196 | .then( responseFromFetch => { 197 | // and put a copy in the cache. 198 | const copy = responseFromFetch.clone(); 199 | fetchEvent.waitUntil( 200 | caches.open(imageCacheName) 201 | .then( imageCache => { 202 | return imageCache.put(request, copy); 203 | }) // end open then 204 | ); // end waitUntil 205 | return responseFromFetch; 206 | }); // end fetch then + return 207 | }) // end match then 208 | ); // end respondWith 209 | return; // go no further 210 | } // end if 211 | // For everything else . . . 212 | fetchEvent.respondWith( 213 | // look for a cached version of the file 214 | caches.match(request) 215 | .then( responseFromCache => { 216 | if (responseFromCache) { 217 | return responseFromCache; 218 | } // end if 219 | // otherwise fetch from the network. 220 | return fetch(request); 221 | }) // end match then 222 | ); // end respondWith 223 | }); // end addEventListener 224 | -------------------------------------------------------------------------------- /chapter06.js: -------------------------------------------------------------------------------- 1 | 2 | staticCache.addAll([ 3 | //[code omitted for brevity] 4 | '/offline.html', 5 | '/fallback.svg' 6 | ]); 7 | 8 | const version = 'V0.05'; 9 | 10 | // When the user requests an image . . . 11 | if (request.headers.get('Accept').includes('image')) { 12 | fetchEvent.respondWith( 13 | // look for a cached version of the image 14 | caches.match(request) 15 | .then( responseFromCache => { 16 | if (responseFromCache) { 17 | return responseFromCache; 18 | } // end if 19 | // otherwise fetch the image from the network 20 | return fetch(request) 21 | .then( responseFromFetch => { 22 | // and put a copy in the cache 23 | const copy = responseFromFetch.clone(); 24 | fetchEvent.waitUntil( 25 | caches.open(imageCacheName) 26 | .then( imageCache => { 27 | return imageCache.put(request, copy); 28 | }) // end open then 29 | ); // end waitUntil 30 | return responseFromFetch; 31 | }) // end fetch then 32 | .catch( error => { 33 | // otherwise show a fallback image. 34 | return caches.match('/fallback.svg'); 35 | }); // end fetch catch + return 36 | }) // end match then 37 | ); // end respondWith 38 | return; // go no further 39 | } // end if 40 | 41 | const version = 'V0.05'; 42 | const staticCacheName = version + 'staticfiles'; 43 | const imageCacheName = 'images'; 44 | const pagesCacheName = 'pages'; 45 | 46 | const cacheList = [ 47 | staticCacheName, 48 | imageCacheName, 49 | pagesCacheName 50 | ]; 51 | 52 | // When the user requests an HTML file . . . 53 | if (request.headers.get('Accept').includes('text/html')) { 54 | fetchEvent.respondWith( 55 | // fetch that page from the network 56 | fetch(request) 57 | .then( responseFromFetch => { 58 | // and put a copy in the cache 59 | const copy = responseFromFetch.clone(); 60 | fetchEvent.waitUntil( 61 | caches.open(pagesCacheName) 62 | .then( pagesCache => { 63 | return pagesCache.put(request, copy); 64 | }) // end open then 65 | ); // end waitUntil 66 | return responseFromFetch; 67 | }) // end fetch then 68 | .catch( error => { 69 | // otherwise look for a cached version of the page 70 | return caches.match(request) 71 | .then( responseFromCache => { 72 | if (responseFromCache) { 73 | return responseFromCache; 74 | } // end if 75 | // otherwise show the fallback page 76 | return caches.match('/offline.html'); 77 | }); // end match then + return 78 | }) // end fetch catch 79 | ); // end respondWith 80 | return; // go no further 81 | } // end if 82 | 83 | if (request.url.includes('/articles/')) { 84 | // logic for article pages goes here. 85 | return; 86 | } 87 | 88 | if (/\/articles\/.+/.test(request.url)) { 89 | // now you’ve got two problems. 90 | return; 91 | } 92 | 93 | // When the requested page is an article . . . 94 | if (/\/articles\/.+/.test(request.url)) { 95 | fetchEvent.respondWith( 96 | // look in the cache 97 | caches.match(request) 98 | .then( responseFromCache => { 99 | if (responseFromCache) { 100 | // fetch a fresh version from the network 101 | fetchEvent.waitUntil( 102 | fetch(request) 103 | .then( responseFromFetch => { 104 | // and update the cache 105 | caches.open(pagesCacheName) 106 | .then( pagesCache => { 107 | return pagesCache.put(request, responseFromFetch); 108 | }) // end open then 109 | }) // end fetch then 110 | ); // end waitUntil 111 | return responseFromCache; 112 | } // end if 113 | // otherwise fetch the page from the network 114 | return fetch(request) 115 | .then( responseFromFetch => { 116 | // and put a copy in the cache 117 | const copy = responseFromFetch.clone(); 118 | fetchEvent.waitUntil( 119 | caches.open(pagesCacheName) 120 | .then( pagesCache => { 121 | return pagesCache.put(request, copy); 122 | }) // end open then 123 | ); // end waitUntil 124 | return responseFromFetch; 125 | }) // end fetch then 126 | .catch( error => { 127 | // otherwise show the fallback page 128 | return caches.match('/offline.html'); 129 | }); // end fetch catch + return 130 | }) // end match then 131 | ); // end respondWith 132 | return; // go no further 133 | } // end if 134 | 135 | if (responseFromCache) { 136 | // fetch a fresh version from the network 137 | fetchEvent.waitUntil( 138 | fetch(request) 139 | .then (responseFromFetch => { 140 | // and update the cache 141 | caches.open(imageCacheName) 142 | .then( imageCache => { 143 | return imageCache.put(request, responseFromFetch); 144 | }); // end open then 145 | }) // end fetch then 146 | ); // end waitUntil 147 | return responseFromCache; 148 | } // end if 149 | -------------------------------------------------------------------------------- /chapter07.js: -------------------------------------------------------------------------------- 1 | function trimCache(cacheName, maxItems) { 2 | caches.open(cacheName) 3 | .then( cache => { 4 | cache.keys() 5 | .then(items => { 6 | if (items.length > maxItems) { 7 | cache.delete(items[0]) 8 | .then( 9 | trimCache(cacheName, maxItems) 10 | ); // end delete then 11 | } // end if 12 | }); // end keys then 13 | }); // end open then 14 | } // end function 15 | 16 | addEventListener('message', messageEvent => { 17 | // do something with messageEvent 18 | }); 19 | 20 | if (navigator.serviceWorker) { 21 | navigator.serviceWorker.register('/serviceworker.js'); 22 | if (navigator.serviceWorker.controller) { 23 | // A service worker is up and running! 24 | } 25 | } 26 | 27 | if (navigator.serviceWorker) { 28 | navigator.serviceWorker.register('/serviceworker.js'); 29 | if (navigator.serviceWorker.controller) { 30 | window.addEventListener('load', function () { 31 | navigator.serviceWorker.controller.postMessage('clean up caches'); 32 | }); 33 | } 34 | } 35 | 36 | addEventListener('message', messageEvent => { 37 | console.log(messageEvent.data); 38 | }); 39 | 40 | addEventListener('message', messageEvent => { 41 | if (messageEvent.data == 'clean up caches') { 42 | trimCache(pagesCacheName, 20); 43 | trimCache(imageCacheName, 50); 44 | } 45 | }); 46 | 47 | function stashInCache(request, cacheName) { 48 | // fetch the file 49 | fetch(request) 50 | .then( responseFromFetch => { 51 | // open the cache 52 | caches.open(cacheName) 53 | .then( theCache => { 54 | // put the file into the cache 55 | return theCache.put(request, responseFromFetch); 56 | }); // end open then 57 | }); // end fetch then 58 | } // end function 59 | 60 | async function stashInCache(request, cacheName) { 61 | // fetch the file 62 | const responseFromFetch = await fetch(request); 63 | // open the cache 64 | const theCache = await caches.open(cacheName); 65 | // put the file into the cache 66 | return await theCache.put(request, responseFromFetch); 67 | } 68 | 69 | fetchEvent.respondWith( 70 | fetch(request) 71 | ); // end respondWith 72 | 73 | fetchEvent.respondWith( 74 | async function() { 75 | return await fetch(request); 76 | }() // end async function 77 | ); // end respondWith 78 | 79 | fetchEvent.respondWith( 80 | // try fetching the file from the network 81 | fetch(request) 82 | .catch( error => { 83 | // otherwise look for a cached version of the file 84 | return caches.match(request) 85 | }) // end fetch catch 86 | ); // end respondWith 87 | 88 | fetchEvent.respondWith( 89 | async function() { 90 | try { 91 | // try fetching the file from the network 92 | return await fetch(request); 93 | } // end try 94 | catch (error) { 95 | // otherwise look for a cached version of the file 96 | return await caches.match(request); 97 | } // end catch 98 | }() // end async function 99 | ); // end respondWith 100 | 101 | fetchEvent.respondWith( 102 | // try fetching the file from the network 103 | fetch(request) 104 | .catch( error => { 105 | // otherwise look for a cached version of the file 106 | return caches.match(request) 107 | .then( responseFromCache => { 108 | if (responseFromCache) { 109 | return responseFromCache; 110 | } // end if 111 | // otherwise show the fallback page 112 | return caches.match('/offline.html'); 113 | }); // end return match then 114 | }); // end fetch catch 115 | ); // end respondWith 116 | 117 | fetchEvent.respondWith( 118 | async function() { 119 | try { 120 | // try fetching the file from the network 121 | return await fetch(request); 122 | } // end try 123 | catch (error) { 124 | // otherwise look for a cached version of the file 125 | const responseFromCache = await caches.match(request); 126 | if (responseFromCache) { 127 | return responseFromCache; 128 | } // end if 129 | // otherwise show the fallback page 130 | return caches.match('/offline.html'); 131 | } // end catch 132 | }() // end async function 133 | ); // end respondWith 134 | -------------------------------------------------------------------------------- /chapter08.js: -------------------------------------------------------------------------------- 1 | // Open the cache of pages. 2 | caches.open('pages') 3 | .then( pagesCache => { 4 | pagesCache.keys() 5 | .then(keys => { 6 | let markup = ''; 7 | // Loop through each item in the cache. 8 | keys.forEach( request => { 9 | // Make a link to the URL of each page. 10 | markup += `${data.description}
`; 102 | } 103 | }); 104 | // Finally, display the list of links. 105 | document.getElementById('history').innerHTML = markup; 106 | }); // end keys then 107 | }); // end open then 108 | --------------------------------------------------------------------------------