chaihongjun.me

service worker配置优化版

service worker配置优化版

上一篇文章《service worker简单配置》已经展现出一个方案用来缓存文件,思路是将需要缓存的文件以白名单的形式枚举出来,这篇文章介绍的方法则是反向的思路,黑名单的方式,将不需要缓存的文件域枚举出来,一般都是第三方的库文件为主。

首先一样是在页面注册serviceworker:

if ('serviceWorker' in navigator) {
 navigator.serviceWorker.register('/sw.js');
}

这里注册在的文件名叫sw.js,并且是在网站根目录,所有的页面都是这样注册,然后是sw.js的详细配置:

'use strict';

const version = 'v20180608';
const __DEVELOPMENT__ = false;
const __DEBUG__ = false;
const offlineResources = [   //离线断网的时候提供友好界面
  '/',
  '/offline.html',
  '/offline.svg'
];

const ignoreFetch = [           //这里是需要忽略的第三方的域名
  /https?:\/\/cdn.bootcss.com\//,
  /https?:\/\/zz.bdstatic.com\//,
  /https?:\/\/s.360.cn\//,
  /https?:\/\/s.ssl.qhres.com\//,
  /https?:\/\/hm.baidu.com\//,
  /https?:\/\/s19.cnzz.com\//,
  /https?:\/\/sp0.baidu.com\//,
  /https?:\/\/tag.baidu.com\//,
  /https?:\/\/msite.baidu.com\//,
  /https?:\/\/s.bdstatic.com\//,
  /https?:\/\/timg01.bdimg.com\//,
];


//////////
// Install
//////////
function onInstall(event) {
  log('install event in progress.');

  event.waitUntil(updateStaticCache());
}

function updateStaticCache() {
  return caches
    .open(cacheKey('offline'))
    .then((cache) => {
      return cache.addAll(offlineResources);
    })
    .then(() => {
      log('installation complete!');
    });
}

////////
// Fetch
////////
function onFetch(event) {
  const request = event.request;

  if (shouldAlwaysFetch(request)) {
    event.respondWith(networkedOrOffline(request));
    return;
  }

  if (shouldFetchAndCache(request)) {
    event.respondWith(networkedOrCached(request));
    return;
  }

  event.respondWith(cachedOrNetworked(request));
}

function networkedOrCached(request) {
  return networkedAndCache(request)
    .catch(() => { return cachedOrOffline(request) });
}

// Stash response in cache as side-effect of network request
function networkedAndCache(request) {
  return fetch(request)
    .then((response) => {
      var copy = response.clone();
      caches.open(cacheKey('resources'))
        .then((cache) => {
          cache.put(request, copy);
        });

      log("(network: cache write)", request.method, request.url);
      return response;
    });
}

function cachedOrNetworked(request) {
  return caches.match(request)
    .then((response) => {
      log(response ? '(cached)' : '(network: cache miss)', request.method, request.url);
      return response ||
        networkedAndCache(request)
          .catch(() => { return offlineResponse(request) });
    });
}

function networkedOrOffline(request) {
  return fetch(request)
    .then((response) => {
      log('(network)', request.method, request.url);
      return response;
    })
    .catch(() => {
      return offlineResponse(request);
    });
}

function cachedOrOffline(request) {
  return caches
    .match(request)
    .then((response) => {
      return response || offlineResponse(request);
    });
}

function offlineResponse(request) {
  log('(offline)', request.method, request.url);
  if (request.url.match(/\.(jpg|png|gif|svg|jpeg)(\?.*)?$/)) {
    return caches.match('/offline.svg');
  } else {
    return caches.match('/offline.html');
  }
}

///////////
// Activate
///////////
function onActivate(event) {
  log('activate event in progress.');
  event.waitUntil(removeOldCache());
}

function removeOldCache() {
  return caches
    .keys()
    .then((keys) => {
      return Promise.all( // We return a promise that settles when all outdated caches are deleted.
        keys
         .filter((key) => {
           return !key.startsWith(version); // Filter by keys that don't start with the latest version prefix.
         })
         .map((key) => {
           return caches.delete(key); // Return a promise that's fulfilled when each outdated cache is deleted.
         })
      );
    })
    .then(() => {
      log('removeOldCache completed.');
    });
}

function cacheKey() {
  return [version, ...arguments].join(':');
}

function log() {
  if (developmentMode()) {
    console.log("SW:", ...arguments);
  }
}

function shouldAlwaysFetch(request) {
  return __DEVELOPMENT__ ||
    request.method !== 'GET' ||
      ignoreFetch.some(regex => request.url.match(regex));
}

function shouldFetchAndCache(request) {
  return ~request.headers.get('Accept').indexOf('text/html');
}

function developmentMode() {
  return __DEVELOPMENT__ || __DEBUG__;
}

log("Hello from ServiceWorker land!", version);

self.addEventListener('install', onInstall);

self.addEventListener('fetch', onFetch);

self.addEventListener("activate", onActivate);

 

知识共享许可协议本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。作者:柴宏俊»