evantianx / Bloooooooog

Place to record what I thought and learned
0 stars 0 forks source link

Service Worker #48

Open evantianx opened 7 years ago

evantianx commented 7 years ago

参考文章: Service Worker gotchas

evantianx commented 7 years ago

注册 Service Worker

For example, the Google I/O 2016 web app features a short animation before transitioning to the main screen. Our team found that kicking off the service worker registration during the animation could lead to jankiness on low-end mobile devices. Rather than giving users a poor experience, we delayed service worker registration until after the animation, when the browser was most likely to have a few idle seconds.

Similarly, if your web app uses a framework that performs additional setup after the page has loaded, look for a framework-specific event that signals when that work is done.

这意味着若页面载入存在动画,则应在动画结束之后再进行注册:

if('serviceWorker' in navigator) {
  document.querySelector('.hero').addEventListener('animationend', function () {
    // service worker is registered only when the animation ends
    navigator.serviceWorker.register('/serviceworker.js');
  });
}

// ---

App.init({
  // config
  complete: function() {
    // service worker is registered only when the app is initiated
    if('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/serviceworker.js');
    }
  }
});

当然,如果你的网站足够简单,那么只需考虑在页面加载完毕之后再注册 Service Worker:

if('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/serviceworker.js');
  });
}
evantianx commented 7 years ago

HTTPS 和 localhost

考虑到安全因素,使用 Service Worker 必须通过 HTTPS 协议或者本地 localhost。

开发环境中,Service Worker 只可以在 localhost 上生效,其他如内网 IP 之类的无效。

evantianx commented 7 years ago

作用范围

只能作用于当前路径和子路径。

不能同时作用于主域名和子域名,如kollegorna.se/serviceworker.js不能作用于labs.kollegorna.se

evantianx commented 7 years ago

ES6语法

最佳实践是: 在注册 Service Worker 时,使用 ES5 语法;在内部使用 ES6 语法。

evantianx commented 7 years ago

添加离线页面

提高用户体验,可以添加一个离线页面。

evantianx commented 7 years ago

生命周期和事件

lifecycle-events-hierarchy

每次用户访问你的网站的时候,浏览器就会下载 worker 文件。如果之前访问过且该文件已经有缓存,那么浏览器就会进行比对。如果发现有差异,则会认为 worker 文件过期, 所以会重新注册 service worker,然后删除旧的 worker 文件。此即为 work 文件的生命周期。

install

在一个生命周期内只会触发一次。负责注册 service worker 以及初始化页面和样式

self.addEventListener('install', event => {
  // ...
})

activate

紧接着 install 事件,activate 事件触发了。同样一个生命周期内只会触发一次。它的作用在于删除过期的缓存。

self.addEventListener('activate', event => {
  // ...
})

fetch

拦截 HTTP 请求。每个 HTTP 请求都会有单独的 fetch 事件触发。可以用来做回调,决定页面重新加载还是从缓存加载。

self.addEventListener('fetch', event => {
  // ...
})
evantianx commented 7 years ago

critical 和 non-critical 资源

首次加载时一定要精简要下载的资源。原因在于用户可能不会在页面停留很久或者网络情况不佳。

const criticalResources = [
        '/',
        '/offline/',
        '/assets/css/main.css',
        '/assets/js/main.js'
      ],

      // 异步缓存文件
      cacheCriticals = () => {
        return caches.open(version).then( cache => {
          return cache.addAll(criticalResources);
        });
      };

self.addEventListener('install', event => {
  event.waitUntil(cacheCriticals().then( () => self.skipWaiting() ));
});

分清主次之后,我们进一步改进:

const otherResources = [
        '/about/',
        '/contact/',
        '/services/'
      ],

      cacheCriticals = () => {
        return caches.open(version).then( cache => {
          cache.addAll(otherResources); // important, but not critical resources
          return cache.addAll(criticalResources); // critical resources
        });
      };