這是配置的sw.jsjavascript
已測試,是OK的.html
'use strict'; const version = 'v2'; const __DEVELOPMENT__ = false; const __DEBUG__ = true; const offlineResources = [ './tt.html', './images/1.png', // '/imgerror.jpg', // '/favicon.ico' ]; const ignoreCache = [ /https?:\/\/hm.baidu.com\//, /https?:\/\/www.google-analytics.com\//, /http?:\/\/resource.haorooms.com\//, /https?:\/\/www.haorooms.com\/admin/, /https?:\/\/github.com\//, // /https?:\/\/z4.cnzz.com\//, ]; // 慎重使用全局可變變量,由於 serviceWork 不可控的中止和重啓,會致使它們的取值在後續讀取時沒法預測 let port; /** * common function */ function developmentMode() { return __DEVELOPMENT__ || __DEBUG__; } function cacheKey() { return [version, ...arguments].join(':'); } function log() { if (developmentMode()) { console.log("SW:", ...arguments); } } // 不須要緩存的請求 function shouldAlwaysFetch(request) { return __DEVELOPMENT__ || request.method !== 'GET' || ignoreCache.some(regex => request.url.match(regex)); } // 緩存 html 頁面 function shouldFetchAndCache(request) { return (/text\/html/i).test(request.headers.get('Accept')); } // 發送 Notification 通知 function sendNotify(title, options, event) { if (Notification.permission !== 'granted') { log('Not granted Notification permission.'); // 無受權時,向來源頁面申請受權 if (port && port.postMessage) { port.postMessage({ type: 'applyNotify', info: { title, options } }); } return; } const notificationPromise = self.registration.showNotification(title || 'Hi:', Object.assign({ body: '這是一個通知示例', icon: './images/1.png', requireInteraction: true, // tag: 'push' }, options)); return event && event.waitUntil(notificationPromise); } /** * onClickNotify */ function onClickNotify(event) { event.notification.close(); const url = "https://www.baidu.com"; event.waitUntil( self.clients.matchAll({ type: "window" }) .then(() => { if (self.clients.openWindow) { return self.clients.openWindow(url); } }) ); } /** * Install 安裝 */ function onInstall(event) { log('install event in progress.'); event.waitUntil( caches.open(cacheKey('offline')) .then(cache => cache.addAll(offlineResources)) .then(() => log('installation complete! version: ' + version)) .then(() => self.skipWaiting()) ); } /** * Fetch */ // 當網絡離線或請求發生了錯誤,使用離線資源替代 request 請求 function offlineResponse(request) { log('(offline)', request.method, request.url); if (request.url.match(/\.(jpg|png|gif|svg|jpeg)(\?.*)?$/)) { return caches.match('./imgerror.jpg'); } else { return caches.match('./offline.html'); } } // 從緩存讀取或使用離線資源替代 function cachedOrOffline(request) { return caches .match(request) .then((response) => response || offlineResponse(request)); } // 從網絡請求,並將請求成功的資源緩存 function networkedAndCache(request) { return fetch(request) .then(response => { const copy = response.clone(); caches.open(cacheKey('resources')) .then(cache => { cache.put(request, copy); }); log("(network: cache write)", request.method, request.url); return response; }); } // 優先從 cache 讀取,讀取失敗則從網絡請求並緩存。網絡請求也失敗,則使用離線資源替代 function cachedOrNetworked(request) { return caches.match(request) .then((response) => { log(response ? '(cached)' : '(network: cache miss)', request.method, request.url); return response || networkedAndCache(request) .catch(() => offlineResponse(request)); }); } // 優先從網絡請求,失敗則使用離線資源替代 function networkedOrOffline(request) { return fetch(request) .then(response => { log('(network)', request.method, request.url); return response; }) .catch(() => offlineResponse(request)); } function onFetch(event) { const request = event.request; // 應當永遠從網絡請求的資源 // 若是請求失敗,則使用離線資源替代 if (shouldAlwaysFetch(request)) { log('AlwaysFetch request: ', event.request.url); event.respondWith(networkedOrOffline(request)); return; } // 應當從網絡請求並緩存的資源 // 若是請求失敗,則嘗試從緩存讀取,讀取失敗則使用離線資源替代 if (shouldFetchAndCache(request)) { event.respondWith( networkedAndCache(request).catch(() => cachedOrOffline(request)) ); return; } event.respondWith(cachedOrNetworked(request)); } /** * Activate */ function removeOldCache() { return caches .keys() .then(keys => Promise.all( // 等待全部舊的資源都清理完成 keys .filter(key => !key.startsWith(version)) // 過濾不須要刪除的資源 .map(key => caches.delete(key)) // 刪除舊版本資源,返回爲 Promise 對象 ) ) .then(() => { log('removeOldCache completed.'); }); } function onActivate(event) { log('activate event in progress.'); event.waitUntil(Promise.all([ // 更新客戶端 self.clients.claim(), removeOldCache() ])) } /** * onPush */ function onPush(event) { log('onPush ', event); sendNotify('Hi:', { body: `發生了一次 Push 同步事件 ~` }, event); } /** * onSync */ function onSync(event) { log('onSync', event); sendNotify('Hi:', { body: `發生了一次 Sync 同步事件 ~` }, event); } /** * onMessage */ function onMessage(event) { log('onMessage', event); if (event.ports) { port = event.ports[0]; } if (!event.data) { return; } // 若是是要求一條通知,則發送 if (event.data.type === 'notify') { const { title, options } = event.data.info || {}; sendNotify(title, options, event); } } log("Hello from ServiceWorker land!", version); self.addEventListener('install', onInstall); self.addEventListener('fetch', onFetch); self.addEventListener("activate", onActivate); self.addEventListener("push", onPush); self.addEventListener("sync", onSync); self.addEventListener('message', onMessage); self.addEventListener("notificationclick", onClickNotify);