FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
363 stars 39 forks source link

ServiceWorkers那些事儿 #131

Open FrankKai opened 5 years ago

FrankKai commented 5 years ago

https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers

FrankKai commented 5 years ago
FrankKai commented 5 years ago

Service Workers解决什么问题?

用户断网导致的离线问题。

Service Workers哪里好?

FrankKai commented 5 years ago

基础架构

1.注册serviceWorkerContainer.register()抓取并注册service worker URL。 2.作用域service worker工作在ServiceWrokerGlobalScope,无DOM权限。 3.监听此时可以处理events了。 4.安装中获取到权限后,worker可以开始安装。Install事件会首先发送到service worker(此时可以填充数据到IndexedDB,缓存网站静态资源)。这与安装一个原生app一样,此时app可以离线使用了。 5.安装成功oninstall处理器完成后,service worker安装成功。 6.激活当前service worker安装成功后,service worker收到一个activate event。onactivate事件主要用来清除上一个版本的Service worker脚本的资源。 7.service worker控制页面service worker此时开始控制页面,但仅仅能控制register()后开启的页面。document在有没有service worker的情况下都可以工作,所以若service worker想控制document,需要重新加载。

Service Worker生命周期图

image

Service Worker事件图

image

FrankKai commented 5 years ago

注册一个worker

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw-test/sw.js', {scope: '/sw-test/'})
  .then(function(reg) {
    // registration worked
    console.log('Registration succeeded. Scope is ' + reg.scope);
  }).catch(function(error) {
    // registration failed
    console.log('Registration failed with ' + error);
  });
}

偶尔会注册失败会是什么原因?

image

其他注意事项:

FrankKai commented 4 years ago

安装和激活:填充你的缓存

self.addEventListener('install', (event)=>{
    event.waitUntil(
        caches.open('v1').then((cache)=>{
            return cache.addAll([
                './sw-test/',
                './sw-test/index.html',
                './sw-test/style.css',
                './sw-test/app.js',
                './sw-test/image-list.js',
                './sw-test/star-wars-logo.jpg',
                './sw-test/gallery',
                './sw-test/gallery/bountryHunters.jpg',
                './sw-test/gallery/myLittleVader.jpg',
                './sw-test/gallery/snowTroppers.jpg'
            ])
        })
    )
})
  1. 在这里我们在self上添加了一个install事件监听器,然后使用ExtendableEvent.watiUntil()方法到事件中-这样可以确保service worker直到waitUntil方法成功执行后才能install。
  2. 在waitUntil内部,我们用caches.open方法创建了一个新的cache,名字叫v1,意思这是我们网站的资源cache的第一个版本。 它返回一个带着已创建cache的promise;一旦resolve出来,我们可以调用cache的addAll方法,addAll方法接受一个包含了将要缓存的资源的相对origin的URL数组。
  3. 如果promise被reject出去,install失败,而且worker不能做任何事。这是ok的,修复bug以后可以下次注册发生后再次尝试。
  4. 一次成功的安装之后,service worker就被激活了。service worker第一次安装或者激活实际上没有太大的意义,但是在service worker更新的时候有很重大的意义。

注意:

FrankKai commented 4 years ago

请求自定义响应

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
  );
});

一个关于fetch和service worker很好的例子

  1. Response()构造器可以自定义响应,下面的这个返回一个普通的字符串。
    new Response('Hello from your friendly neighbourhood service worker!');
  2. Response中可以自定义头,headers中写即可。
    new Response('<p>Hello from your friendly neighbourhood service worker!</p>', {
    headers: { 'Content-Type': 'text/html' }
    });
  3. 如果没有匹配到cache中的资源,可以fetch资源的默认网络请求。在网络好用的情况下。
    fetch(event.request);
  4. 网络不可用的情况下,可以访问到本地的静态文件。
    caches.match('./fallback.html');
  5. 在event的Request对象中,可以查询到详细的请求信息。
    event.request.url
    event.request.method
    event.request.headers
    event.request.body
FrankKai commented 4 years ago

恢复错误请求

可以像下面这样处理异常:

self.addEventListener('fetch', (event)=>{
    event.respondWith(
        caches.match(event.request).then((response)=>{
            return response || fetch(event.request).then((response) => {
                 return caches.open('v1').then((cache) => {
                     cache.put(event.request, response.clone());
                     return response;
                });  
            });
        }).catch(()=> {
            return caches.match('./sw-test/gallery/myLittleVader.jpg');
        })
    )
})
FrankKai commented 4 years ago

更新service worker

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v2').then((cache) => {
      return cache.addAll([
        './sw-test/',
        './sw-test/index.html',
        './sw-test/style.css',
        './sw-test/app.js',
        './sw-test/image-list.js',

        …

        // include other new resources for the new version...
      ]);
    })
  );
});

删除旧cache