gnosis23 / hello-world-blog

还是 issues 里面写文章方便
https://bohao.work
0 stars 0 forks source link

ServiceWorker 挖个坑 #46

Open gnosis23 opened 5 years ago

gnosis23 commented 5 years ago

没事找个课程学习下 The Benefits of Offline First

还挺受益的

Register

注册 ServiceWorker,注意默认路径能管的范围是 /path/

if (navigator.serviceWorker) {
  navigator.serviceWorker.register('/path/sw.js').then(...).catch(...)
}

Lifecyle

当修改 ServiceWorker 后,F5 后新更新的不会生效,必须等老的结束后才行。 可通过 DevTools 观察 Waiting 状态 一种刷新方法是转到其他页面,再转回来;另一种是按 Shift + 刷新 ;

Hijacking Requests

最暴力的劫持请求,参考学习下 Response 对象。

self.addEventListener('fetch', function(event) {
  event.respondWith(new Response('<div class="a-winner-is-me">666</div>', {
    headers: {
      'Content-Type': 'text/html;charset=utf-8'
    }
  }));
});

FetchEvent.respondWith 同时也接受 fetch 对象

Cache API

主要 API

缓存时机 install

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open('wittr-static-v1').then(function (cache) {
      return cache.addAll([
        '/',
        'js/main.js',
        'css/main.css',
      ]);
    })
  );
});

使用时机 fetch

self.addEventListener('fetch', function(event) {
  // respond with an entry from the cache if there is one.
  // If there isn't, fetch from the network.
  event.respondWith(
    caches.open('wittr-static-v1').then(function (cache) {
      return cache.match(event.request.url);
    }).then(response => {
      return response ? response : fetch(event.request);
    })
  );
});

Update Static

清理旧缓存

在获取不到新的SW时,旧的SW能够使用缓存;而当新的SW能运行时,干掉旧的缓存。 这个时机为 activate

gnosis23 commented 5 years ago

更新事件顺序

在某个时间点,您的 Service Worker 需要更新。 此时,您需要遵循以下步骤:

推送通知

介绍几个名词:

register 返回的 ServiceWorkerRegistration 对象可以感知新的更新,我们可以进行一些相关操作;

    navigator.serviceWorker.register('service-worker.js', {
        scope: './'
    }).then(function (registration) {
        var serviceWorker;
        // returns null during a force-refresh request (Shift + refresh) or if there is no active worker.
        if (!navigator.serviceWorker.controller) return;
        if (registration.installing) {
            // installing new ServiceWorker
            serviceWorker = registration.installing;
            document.querySelector('#kind').textContent = 'installing';
        } else if (registration.waiting) {
            // new ServiceWorker is waiting
            serviceWorker = registration.waiting;
            document.querySelector('#kind').textContent = 'waiting';
        } else if (registration.active) {
            serviceWorker = registration.active;
            document.querySelector('#kind').textContent = 'active';
        }
        // waiting for update
    }).catch (function (error) {
        // Something went wrong during registration. The service-worker.js file
        // might be unavailable or contain a syntax error.
    });

手动更新

替换当前 service worker: ServiceWorkerGlobalScope.skipWaiting()

gnosis23 commented 5 years ago

平稳降级

ServiceWorker 极容易出错,所以线上要有降级机制,也就是彻底干掉它

  fetch('/run-sw').then(response => {
    return response.json();
  }).then(response => {
    var allow = response.allow;
    if (allow) {
      navigator.serviceWorker.register('./sw.js').then(reg => {
        console.log('register success');
      }).catch(err => {
        console.log(err);
      });
    } else {
      navigator.serviceWorker.getRegistration('./sw.js').then(reg => {
        if (reg) {
          reg.unregister();
          // clear cache
        }
      })
    }
  })

错误处理

self.addEventListener('error', function(e) {
  // ...
});

self.addEventListener('unhandledrejection', function(e) {
  // ...
})
gnosis23 commented 5 years ago

参考资料

gnosis23 commented 5 years ago

Workbox 搞起

一些参考资料

Workbox CLI

workbox-config.js

配置 precache 文件、源路径、目标路径等等

precache

在 install 阶段保存的文件,只有全部下好才算 install 成功

route

对各个路由采用不同的 Strategy 。

workbox.routing.registerRoute(
  /(.*)articles(.*)\.(?:png|gif|jpg)/,
  workbox.strategies.cacheFirst({
    cacheName: 'images-cache',
    plugins: [
      new workbox.expiration.Plugin({
        maxEntries: 50,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      })
    ]
  })
);