如何把网站改成PWA( 三 )

注意 , 最后的self.clients.claim()方法设置本身为active的service worker 。
Fetch 事件当有网络请求时这个事件被触发 。它调用respondWith()方法来劫持 GET 请求并返回:

  1. 缓存中的一个静态资源 。
  2. 如果 #1 失败了 , 就用 Fetch API(这与 service worker 的fetch 事件没关系)去网络请求这个资源 。然后将这个资源加入缓存 。
  3. 如果 #1 和 #2 都失败了 , 那就返回一个适当的值 。
// application fetch network dataself.addEventListener('fetch', event => {// abandon non-GET requestsif (event.request.method !== 'GET') return;let url = event.request.url;event.respondWith(caches.open(CACHE).then(cache => {return cache.match(event.request).then(response => {if (response) {// return cached fileconsole.log('cache fetch: ' + url);return response;}// make network requestreturn fetch(event.request).then(newreq => {console.log('network fetch: ' + url);if (newreq.ok) cache.put(event.request, newreq.clone());return newreq;})// app is offline.catch(() => offlineAsset(url));});}));});最后这个offlineAsset(url)方法通过几个辅助函数返回一个适当的值:
// is image URL?let iExt = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'].map(f => '.' + f);function isImage(url) {return iExt.reduce((ret, ext) => ret || url.endsWith(ext), false);}// return offline assetfunction offlineAsset(url) {if (isImage(url)) {// return imagereturn new Response('<svg role="img" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg"><title>offline</title><path d="M0 0h400v300H0z" fill="#eee" /><text x="200" y="150" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="50" fill="#ccc">offline</text></svg>',{ headers: {'Content-Type': 'image/svg+xml','Cache-Control': 'no-store'}});}else {// return pagereturn caches.match(offlineURL);}}offlineAsset()方法检查是否是一个图片请求 , 如果是 , 那么返回一个带有 “offline” 字样的 SVG 。如果不是 , 返回 offlineURL 页面 。
开发者工具提供了查看 Service Worker 相关信息的选项:
 
如何把网站改成PWA

文章插图
 
2020042302.png
在开发者工具的 Cache Storage 选项列出了所有当前域内的缓存和所包含的静态文件 。当缓存更新的时候 , 你可以点击左下角的刷新按钮来更新缓存:
 
如何把网站改成PWA

文章插图
 
2020042303.png
 
不出意料 ,  Clear storage 选项可以删除你的 service worker 和缓存:
 
如何把网站改成PWA

文章插图
 
2020042304.png
2.4 第四步:创建一个可用的离线页面离线页面可以是一个静态页面 , 来说明当前用户请求不可用 。然而 , 我们也可以在这个页面上列出可以访问的页面链接 。
在main.js中我们可以使用 Cache API。然而API 使用promises , 在不支持的浏览器中会引起所有javascript运行阻塞 。为了避免这种情况 , 我们在加载另一个 /js/offlinepage.js 文件之前必须检查离线文件列表和是否支持 Cache API。
// load script to populate offline page listif (document.getElementById('cachedpagelist') && 'caches' in window) {var scr = document.createElement('script');scr.src = https://www.isolves.com/it/cxkf/bk/2020-04-26/'/js/offlinepage.js';scr.async = 1;document.head.appendChild(scr);}/js/offlinepage.js locates the most recent cache by version name, 取到所有 URL的key的列表 , 移除所有无用 URL , 排序所有的列表并且把他们加到 ID 为cachedpagelist的 DOM 节点中:
// cache nameconstCACHE = '::PWAsite',offlineURL = '/offline/',list = document.getElementById('cachedpagelist');// fetch all cacheswindow.caches.keys().then(cacheList => {// find caches by and order by most recentcacheList = cacheList.filter(cName => cName.includes(CACHE)).sort((a, b) => a - b);// open first cachecaches.open(cacheList[0]).then(cache => {// fetch cached pagescache.keys().then(reqList => {let frag = document.createDocumentFragment();reqList.map(req => req.url).filter(req => (req.endsWith('/') || req.endsWith('.html')) && !req.endsWith(offlineURL)).sort().forEach(req => {letli = document.createElement('li'),a = li.appendChild(document.createElement('a'));a.setAttribute('href', req);a.textContent = a.pathname;frag.appendChild(li);});if (list) list.appendChild(frag);});})});


推荐阅读