pwa离线缓存原理

作者: brandonxiang | 来源:发表于2018-09-07 17:05 被阅读203次

主线程

ServiceWorker既然命名为worker,很大一部分原因就是它和WebWorker相关。它是第二个线程,不会影响dom渲染的主线程,两个Worker之间的通讯是基于postMessage。 chrome://inspect/#service-workers 就可以查看,在当前浏览器中,正在注册的 SW。另外,还有一个 chrome://serviceworker-internals,用来查看当前浏览器中,所有注册好的 SW。

基于HTTPS

现在,开发一个网站没用 HTTPS,估计都没好意思放出自己的域名(太 low)。HTTPS 不仅仅可以保证你网页的安全性,还可以让一些比较敏感的 API 完美的使用。值得一提的是,SW 是基于 HTTPS 的,所以,如果你的网站不是 HTTPS,那么基本上你也别想了 SW。

Scope作用域

一个sw.js并不能接管一个站点所有的页面,它只能在所在路由底下起到作用。意思就是如果你在//example.com/foo/bar.js里注册了一个 SW,那么它默认的作用域为//example.com/foo/

生命周期

注册

ServiceWorker.js(又名sw.js)是一个独立js,页面注册在浏览器支持的情况下,注册sw.js来控制Service Worker缓存。register将会触发安装声明周期。

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('ServiceWorker registration successful with scope: ',    registration.scope);
  }).catch(function(err) {
    console.log('ServiceWorker registration failed: ', err);
  });
}

install

注册完成后会出发安装的生命周期,把设置好的静态文件,采用Service Worker的缓存方式,使用了Cache API来将资源缓存起来,同时使用e.waitUntil接手一个Promise来等待资源缓存成功,等到这个Promise状态成功后,ServiceWorker进入installed状态,意味着安装完毕。这时候主线程中返回的registration.waiting属性代表进入installed状态的ServiceWorker。

var CACHE_NAME = "my_cache";
var urlsToCache = [
  '/index.html',
  '/css/style.css',
  '/js/script.js'
];
//这里的self代表ServiceWorkerGlobalScope
self.addEventListener('install', function(event) {
//这里的waitUtil会在安装成功之前执行一些预装的操作,但是只建议做一些轻量级和非常重要资源的缓存,减少安装失败的概率。安装成功
//后ServiceWorker状态会从installing变为installed 
event.waitUntil(
        caches.open(CACHE_NAME).then(function(cache) {
             console.log('Opendhe : ',cache);
            return cache.addAll(urlsToCache);
      })
    );
});

skipWaiting

skipWaiting()意味着新 SW 控制了之前用旧 SW 获取的页面,也就是说你的页面有一部分资源是通过旧 SW 获取,剩下一部分是通过新 SW 获取.

activate

安装完,则会进入激活状态。如果之前已有ServiceWorker,这个版本只是对ServiceWorker进行了更新。如果你在event.waitUntil()中传入了一个 Promise,SW 将会缓存住功能性事件(fetch,push,sync等等),直到 Promise 返回 resolve 的时候再触发,也就是说,当你的fetch事件被触发的时候,SW 已经被完全激活了。

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys => Promise.all(
      keys.map(key => {
        if (!expectedCaches.includes(key)) {
          return caches.delete(key);
        }
      })
    )).then(() => {
      // V2控制缓存
    })
  );
});

fetch

fetch请求是有别于xhr请求,sw提供监听拦截fetch的事件,对于命中缓存的数据可以直接返回请求。当接受到 fetch 请求时,会直接返回event.respondWith 得到Promise 结果。这样我们可以捕获页面所有的 fetch 请求。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }
        return fetch(event.request);
      }
    )
  );
});

Redundant

Service Worker 可能以下之一的原因而被废弃(redundant,原意为“多余的,累赘的”)——

  • installing 事件失败
  • activating 事件失败
  • 新的 Service Worker 替换其成为激活态 worker

注意

浏览器获取了新版本的ServiceWorker代码,如果浏览器本身对sw.js进行缓存的话,也不会得到最新代码,所有代码会变成死代码,无法更新。所以对sw文件最好配置成cache-control: no-cache。

后面的介绍中采用sw-register-webpack-plugin来处理sw.js的更新问题

参考

PS

平安人寿科技中心招聘前端工程师,地点深圳

  • 工作年限两年以上
  • 小程序,Vue,兼容IE框架都要懂一点

如果有想法的同学,可以发简历到1542453460@qq.com

相关文章

网友评论

    本文标题:pwa离线缓存原理

    本文链接:https://www.haomeiwen.com/subject/ctncgftx.html