什么时候在事件处理程序之外的服务工作者中的代码运行?

Jef*_*ick 26 service-worker

(我正在解释Rich Harris在" 我希望我早点知道服务工作者的事情 "这个问题上提出的问题.)

如果我的服务工作者中的代码在事件处理程序之外运行,它何时运行?

而且,与此密切相关的是,放入install处理程序并将其完全放在事件处理程序之间有什么区别?

Jef*_*ick 54

通常,在服务工作者的全局范围的"顶级"中的任何事件处理程序之外的代码将在每次启动服务工作线程(/进程)时运行.服务工作者线程可以在任意时间开始(和停止),并且它与它控制的网页的生命周期无关.

(频繁启动/停止服务工作者线程是性能/电池优化,并确保,例如,仅仅因为您浏览到已注册服务工作者的页面,您将不会在后台获得额外的空闲线程. )

另一方面,每次服务工作者线程停止时,任何现有的全局状态都将被销毁.因此,虽然您可以进行某些优化,例如将开放的IndexedDB连接存储在全局状态,希望跨多个事件共享它,但如果线程已在事件处理程序调用之间被杀死,则需要准备重新初始化它们.

与此问题密切相关的是我在install事件处理程序中看到的误解.我看到一些开发人员使用install处理程序来初始化他们然后依赖于其他事件处理程序的全局状态,比如fetch.这很危险,很可能会导致生产中的错误.该install处理器触发每一个服务人员的版本一次,通常是最好的那些依赖于由该版本需要服务人员的版本,比如缓存新的或更新的资源任务使用.在后install处理程序已成功完成,服务职工的给定版本将被视为"安装",以及install处理程序将在服务人员启动以处理不被再次触发,例如,一个fetchmessage事件.

因此,如果存在需要在处理之前初始化的全局状态(例如,fetch事件),则可以在顶级服务工作者全局范围内执行此操作(可选地等待在fetch事件处理程序内部解析的promise 以确保任何异步操作已经完成).难道不是依靠install处理器来建立全球范围内!

这是一个示例,说明了其中的一些要点:

// Assume this code lives in service-worker.js

// This is top-level code, outside of an event handler.
// You can use it to manage global state.

// _db will cache an open IndexedDB connection.
let _db;
const dbPromise = () => {
  if (_db) {
    return Promise.resolve(_db);
  }

  // Assume we're using some Promise-friendly IndexedDB wrapper.
  // E.g., https://www.npmjs.com/package/idb
  return idb.open('my-db', 1, upgradeDB => {
    return upgradeDB.createObjectStore('key-val');
  }).then(db => {
    _db = db;
    return db;
  });
};

self.addEventListener('install', event => {
  // `install` is fired once per version of service-worker.js.
  // Do **not** use it to manage global state!
  // You can use it to, e.g., cache resources using the Cache Storage API.
});

self.addEventListener('fetch', event => {
  event.respondWith(
    // Wait on dbPromise to resolve. If _db is already set, because the
    // service worker hasn't been killed in between event handlers, the promise
    // will resolve right away and the open connection will be reused.
    // Otherwise, if the global state was reset, then a new IndexedDB
    // connection will be opened.
    dbPromise().then(db => {
      // Do something with IndexedDB, and eventually return a `Response`.
    });
  );
});
Run Code Online (Sandbox Code Playgroud)