diff --git a/server/public/cache.js b/server/public/cache.js index 1202151b..71777bc8 100644 --- a/server/public/cache.js +++ b/server/public/cache.js @@ -1,28 +1,23 @@ const CACHE_NAME = 'v0.0'; const URLS_TO_CACHE = ['/', '/index.html']; +const DELAY_BEFORE_SENDING_CACHE = 500; self.addEventListener('fetch', function(event){ if(is_a_ressource(event.request)){ - //console.log("> FETCH RESSOURCE", event.request.url) return fetchRessource(event); }else if(is_an_api_call(event.request)){ - //console.log("> FETCH API", event.request.url) return fetchApi(event); }else if(is_an_index(event.request)){ - //console.log("> FETCH INDEX", event.request.url) return fetchIndex(event); }else{ - //console.log("> FETCH FALLBACK", event.request.url) return cacheFallback(event); } }); self.addEventListener('activate', function(event){ - //console.log("> ACTIVATE") vacuum(event) }); self.addEventListener('install', function(event){ - //console.log("> INSTALL SERVICE WORKER", navigator) if (self.skipWaiting) { self.skipWaiting(); } }) @@ -38,41 +33,10 @@ function is_a_ressource(request){ * cache agressively but refresh the cache if possible */ function fetchRessource(event){ - event.respondWith( - caches.open(CACHE_NAME).then(function(cache){ - return cache.match(event.request) - .then(function(response){ - if(response){ - fetchAndCache(event).catch(nil) - return response; - }else{ - return Promise.reject("OUPS"); - } - }) - .catch(function(err){ - return fetchAndCache(event); - }); - }) - ); - - function fetchAndCache(event){ - // A request is a stream and can only be consumed once. Since we are consuming this - // once by cache and once by the browser for fetch, we need to clone the response as - // seen on https://developers.google.com/web/fundamentals/getting-started/primers/service-workers - const request = event.request.clone(); - - return fetch(request) - .then(function(response){ - if(!response){ return response; } - - // A response is a stream and can only because we want the browser to consume the - // response as well as the cache consuming the response, we need to clone it - const responseToCache = response.clone(); - caches.open(CACHE_NAME).then(function(cache){ - cache.put(event.request, responseToCache); - }); - return response; - }); + if(navigator.standalone === true || navigator.onLine === false){ + event.respondWith(cacheThenNetwork(event.request)) + }else{ + event.respondWith(networkThenCache(event.request)); } } @@ -97,19 +61,11 @@ function is_an_index(request){ return ['login', 'files', 'view', 'logout'].indexOf(pathname(request)[0]) >= 0? true : false; } function fetchIndex(event){ - event.request.url = host(event.request); - event.respondWith( - caches.open(CACHE_NAME).then(function(cache){ - return cache.match('/').then(function(response){ - return response || fetch('/').then(function(response) { - if(response && response.status === 200){ - cache.put('/', response.clone()); - } - return response; - }) - }) - }) - ) + if(navigator.standalone === true || navigator.onLine === false){ + event.respondWith(cacheThenNetwork(event.request)) + }else{ + event.respondWith(networkThenCache(event.request)); + } } @@ -117,21 +73,7 @@ function fetchIndex(event){ // OTHER STUFF //////////////////////////////////////// function cacheFallback(event){ - event.respondWith( - caches.open(CACHE_NAME).then(function(cache){ - return cache.match(event.request).then(function(response){ - if(response){ - return response; - }else{ - return fetch(event.request.clone()) - .then(function(response){ - cache.put(event.request, response.clone()) - return response; - }); - } - }); - }) - ) + event.respondWith(cacheThenNetwork(event.request)); } @@ -158,3 +100,79 @@ function pathname(request){ return request.url.replace(/^http[s]?:\/\/[^\/]*\//, '').split('/') } function nil(e){} + + +function cacheThenNetwork(request){ + return caches.open(CACHE_NAME).then(function(cache){ + return cache.match(request) + .then(function(response){ + if(response){ + fetchAndCache(request).catch(nil) + return response; + }else{ + return Promise.reject("OUPS"); + } + }) + .catch(function(err){ + return fetchAndCache(request); + }); + }); + + + function fetchAndCache(_request){ + // A request is a stream and can only be consumed once. Since we are consuming this + // once by cache and once by the browser for fetch, we need to clone the response as + // seen on https://developers.google.com/web/fundamentals/getting-started/primers/service-workers + return fetch(_request.clone && _request.clone() || _request) + .then(function(response){ + if(!response){ return response; } + + // A response is a stream and can only because we want the browser to consume the + // response as well as the cache consuming the response, we need to clone it + const responseClone = response.clone(); + caches.open(CACHE_NAME).then(function(cache){ + cache.put(_request, responseClone); + }); + return response; + }); + } +} + +function networkThenCache(request){ + let timeoutId; + + return Promise.race([ + cache(request.clone && request.clone() || request), + network(request.clone && request.clone() || request) + ]) + + function network(request){ + return fetch(request) + .then(function(response){ + const responseClone = response.clone(); + caches.open(CACHE_NAME).then(function(cache){ + cache.put(request, responseClone); + }); + return Promise.resolve(response); + }) + .catch(function(){ + return cache(request.clone && request.clone() || request) + }); + } + + function cache(_request){ + return timeout() + .then(function(){ return caches.open(CACHE_NAME)}) + .then(function(_cache){ + return _cache.match(_request); + }); + + function timeout(){ + return new Promise(function(resolve) { + setTimeout(function() { + resolve(); + }, DELAY_BEFORE_SENDING_CACHE); + }); + } + } +}