上一篇说过的manifest离线缓存方法虽然被所有主流浏览器的最新版本所支持,但终究还是在web标准中被废弃了,firefox在控制台会提醒使用Service Worker缓存替代。
但其实Service Worker还远远没有被普遍支持,仅chrome、firefox和opera的新版本支持,Edge和safari的支持尚在开发中,而且Service Worker要求必须在https网站上使用。所以实际上,在相当长的时间内manifest缓存会一直被各大浏览器支持,不会被轻易删除。新标准的普及需要时间,旧标准的完全退出更需要时间,这个时间,可能长于大部分网站的生命周期……
但我还是先试了一下Service Worker,方法同样很简单,第一步先注册Service Worker,类似于manifest方法中在html元素内添加清单文件,只不过这里是在页面注册一个js文件,引入以下js代码即可。
if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/qifu/sw.js').then(function(registration) { console.log('ServiceWorker registration successful with scope: ', registration.scope); }).catch(function(err) { console.log('ServiceWorker registration failed: ', err); }); }); }
注册的这个js文件所在的路径会影响Service Worker的作用域,它在哪个目录下,作用域就包含哪个目录。比如“/qifu/sw.js”就会导致作用域是/qifu/及其下属目录,而放在根目录的话,作用域就是全站。
下面是注册的Service Worker文件内容(/qifu/sw.js)。
var CACHE_NAME = 'qifu'; //缓存名称 var urlsToCache = [ '/qifu/', 'style.css', 'script.js' ]; //要缓存的资源url self.addEventListener('install', function(event) { event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); }); //初始化安装,缓存上面列出的资源 self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { if (response) { return response; } return fetch(event.request); } ) ); }); //拦截所有请求,缓存过则直接返回
首先是安装Service Worker,也就是初始化,告诉浏览器先缓存好哪些内容;然后Service Worker就拦截所有请求,有缓存就直接返回缓存内容。初始化只有第一次以及Service Worker文件有更新后才会触发,否则会被自动跳过。
Service Worker缓存之所以被推出用来替代manifest缓存,一个很重要的原因就是更灵活。比如即使初始化时没有缓存某些文件,也可以在后续用到时自动缓存(具体代码本文不再列出,只比上述代码多几行),而不像manifest一样必须逐一列出要缓存的内容,还不允许通配符CACHE。
由于目前浏览器对于Service Worker的支持尚不广泛,可以同时保留manifest缓存,如果支持的话,浏览器检测到两者并存会自动使用Service Worker。
类似于manifest缓存,每次打开浏览器,会使用缓存的数据,然后浏览器默默查看Service Worker文件有没有更新,只要有哪怕一个字节的变化,就会重新缓存,新内容同样是下次访问生效。(大部分网站可能都为js文件设置了HTTP缓存,目前浏览器在检查Service Worker文件更新时会遵守http header里面设置的缓存时间,但最长24小时,如果超过了这一数值,浏览器会重新下载Service Worker的js文件。)
如果更新后的Service Worker定义了新的缓存名称,通常希望删掉旧的缓存,可以用下面的代码:
self.addEventListener('activate', function(event) { var cacheWhitelist = ['not-delete-cache-a', 'not-delete-cache-b']; //上面是不要删除的缓存名,其余全部删除 event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( cacheNames.map(function(cacheName) { if (cacheWhitelist.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) ); });
好了,就这么简单。
大神,如果是跨域的资源呢?
主站是www.example.com
资源是 asset.example.com/imgs/example.css
之类的路径,怎么安排缓存?
不是大神,纯业余,我自己没尝试过,但是根据网上的描述,引用的跨域资源也是受Service Worker缓存控制的。