为什么 MV3 Chrome 扩展(使用 Service Workers)必须“在事件循环的第一轮注册监听器”?

Kri*_*osh 4 javascript event-loop google-chrome-extension chrome-extension-manifest-v3 chrome-extension-manifest-v2

因此,我正在将使用持久后台页面的 MV2 扩展迁移到 MV3。在 Chrome 迁移指南 [https://developer.chrome.com/docs/extensions/mv3/migration_to_service_workers/#event_listeners] 中,它说:

为了让 Chrome 成功地将事件分派给适当的侦听器,扩展程序必须在事件循环的第一轮注册侦听器。实现此目的最直接的方法是将事件注册移至 Service Worker 脚本的顶层。

当 Service Worker 终止时,与其关联的事件侦听器也会终止。由于事件是在 Service Worker 启动时分派的,因此异步注册事件会导致事件被丢弃,因为首次启动时没有注册侦听器。

我的问题:

  1. 为什么我们必须这样注册呢?如果我们在等待异步操作后注册会有什么问题?
  2. 如果确实当一个 Service Worker 被终止时,与其关联的事件监听器也被终止,那么如果事件监听器都被终止,那么为什么不活动的 Service Worker 会突然变得活动呢?(我假设如果事件侦听器终止,它不会侦听事件。)
// background.js(service worker)
chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.action.setBadgeText({ text: badgeText });

  // Listener is registered asynchronously
  // This is NOT guaranteed to work in Manifest V3/service workers! Dont do this
  chrome.action.onClicked.addListener(handleActionClick);
});
Run Code Online (Sandbox Code Playgroud)

wOx*_*xOm 8

为什么我们必须这样注册呢?

因为这就是内部实现事件注册的方式,让浏览器知道哪些类型的事件应该唤醒工作线程:

  1. 当后台 Service Worker 脚本未运行时,它会在新的 JS 环境中启动,整个脚本从第一行运行到最后一行。
  2. 当调用addListener事件时chrome,API 在内部存储函数引用,并告诉浏览器在内部浏览器数据库中记住该事件名称。
  3. 最后一条语句执行完毕后,浏览器将调用 JS 函数来获取浏览器在上次运行工作程序时所记住的事件(上面的步骤 2)。
  4. 在关闭所有打开的端口并处理所有事件后,不活动计时器将触发(Chrome 中为 30 秒)并且脚本将终止,JS 环境将被完全破坏。

如果我们在等待异步操作后注册会有什么问题?

当后台服务工作线程脚本在事件发生之前未运行时,它会按照上述方式启动,并且您迟来注册的侦听器不会出现在内部 API 数据库中,因此不会调用它,并且您将丢失此事件。

仅当后台服务工作线程脚本在事件触发之前已经运行时,您迟来注册的侦听器才会看到该事件。

如果确实When a service worker is terminated, so are the event listeners associated with it如此,那么如果事件侦听器全部终止,那么不活动的服务工作人员如何突然变得活动?(我假设如果事件侦听器终止,它不会侦听事件。)

事实上,当后台服务工作线程脚本终止时,就像关闭一个选项卡一样,里面什么都没有幸存,它不会监听任何内容,不再有“它”了。

唤醒是通过addListener告诉浏览器记住浏览器进程内部数据库中的事件名称及其过滤器(例如,在 webNavigation 的 webRequest 中)来实现的,每次后台服务工作线程脚本运行时都会发生这种情况(但仅在第一个事件循环的轮次)。当浏览器中发生符合条件的事件时,浏览器将启动扩展程序的后台服务工作线程脚本并按本答案开头所述分派该事件。