事件处理程序之外的 Service Worker 中的代码何时运行? [英] When does code in a service worker outside of an event handler run?

查看:35
本文介绍了事件处理程序之外的 Service Worker 中的代码何时运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(我正在解释 Rich Harris 在我希望我早点知道有关 Service Worker 的问题" 要点.)

(I am paraphrasing question asked by Rich Harris in the "Stuff I wish I'd known sooner about service workers" gist.)

如果我的 Service Worker 中有在事件处理程序之外运行的代码,它何时运行?

If I have code in my service worker that runs outside an event handler, when does it run?

而且,与此密切相关的是,将其置于 install 处理程序内部和将其完全置于事件处理程序外部有什么区别?

And, closely related to that, what is the difference between putting inside an install handler and putting it outside an event handler entirely?

推荐答案

一般来说,在任何事件处理程序之外的代码,在 Service Worker 全局范围的顶级"中,每次 Service Worker 都会运行线程(/进程)启动.Service Worker 线程可能会在任意时间启动(和停止),并且与它控制的网页的生命周期无关.

In general, code that's outside any event handler, in the "top-level" of the service worker's global scope, will run each and every time the service worker thread(/process) is started up. The service worker thread may start (and stop) at arbitrary times, and it's not tied to the lifetime of the web pages it controlled.

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

(Starting/stopping the service worker thread frequently is a performance/battery optimization, and ensures that, e.g., just because you browse to a page that has registered a service worker, you won't get an extra idle thread spinning in the background.)

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

The flip side of that is that every time the service worker thread is stopped, any existing global state is destroyed. So while you can make certain optimizations, like storing an open IndexedDB connection in global state in the hopes of sharing it across multiple events, you need to be prepared to re-initialize them if the thread had been killed in between event handler invocations.

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

Closely related to this question is a misconception I've seen about the install event handler. I have seen some developers use the install handler to initialize global state that they then rely on in other event handlers, like fetch. This is dangerous, and will likely lead to bugs in production. The install handler fires once per version of a service worker, and is normally best used for tasks that are tied to service worker versioning—like caching new or updated resources that are needed by that version. After the install handler has completed successfully, a given version of a service worker will be considered "installed", and the install handler won't be triggered again when the service worker starts up to handle, e.g., a fetch or message event.

因此,如果在处理之前需要初始化全局状态,例如 fetch 事件,您可以在顶级 Service Worker 全局范围内执行此操作(可选地等待承诺在 fetch 事件处理程序中解析以确保任何异步操作都已完成).不要不要依赖 install 处理程序来设置全局范围!

So, if there is global state that needs to be initialized prior to handling, e.g., a fetch event, you can do that in the top-level service worker global scope (optionally waiting on a promise to resolve inside the fetch event handler to ensure that any asynchronous operations have completed). Do not rely on the install handler to set up global scope!

以下是说明其中一些要点的示例:

Here's an example that illustrates some of these points:

// 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`.
    });
  );
});

这篇关于事件处理程序之外的 Service Worker 中的代码何时运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆