事件页面

应用和扩展程序通常需要长时间运行的脚本来管理某些任务或状态,这就是事件页面的作用。事件页面只在需要时加载,当事件页面不活动时就会卸载,以便释放内存和其他系统资源。

从 Chrome 22 的稳定版开始可以使用事件页面,它具有明显的性能优势,尤其在低功耗设备上。请您在开发新的扩展程序时尽可能首先考虑事件页面,而不是持久存在的后台页面,并开始将现有的后台页面迁移到这一新模型。

清单文件

扩展程序的清单文件中注册您的事件页面:

{
  "name": "我的扩展程序",
  ...
  "background": {
    "scripts": ["eventPage.js"],
    "persistent": false
  },
  ...
}

注意,如果没有 "persistent" 键,您将得到一个普通的后台网页。是否持久存在是事件页面与后台网页之间的根本区别。

生命周期

事件页面在“需要”时加载,再次进入空闲状态后卸载。如下是一些可能使事件页面加载的例子:

  • 应用或扩展程序第一次安装或者更新到新版本(为了注册事件)。
  • 事件页面监听的某个事件触发。
  • 内容脚本或其他扩展程序发送消息
  • 扩展程序中的其他视图调用了 runtime.getBackgroundPage

一旦加载后,只要它仍然处于活动状态(例如,调用扩展程序 API 或发出网络请求),事件页面会继续运行。此外,直到所有可见视图(例如弹出窗口)关闭并且所有消息端口都关闭后,事件页面才会卸载。注意,打开某个视图并不会使事件页面载入,只会在载入后防止它关闭。

确保您的事件页面在打开它的事件处理完之后立刻关闭。您可以打开 Chrome 浏览器的任务管理器,观察您的事件页面的生命周期。您的扩展程序对应的条目在进程列表中出现时您可以注意观察,看出您的事件页面的加载与卸载。

一旦事件页面保持一段时间(几秒钟)的空闲状态,将触发 runtime.onSuspend 事件。事件页面在强制卸载之前,还有几秒钟的时间来处理该事件。如果在这段时间内产生了通常会使事件页面载入的事件,卸载操作将取消,并产生 runtime.onSuspendCanceled 事件。

事件注册

Chrome 浏览器会追踪应用或扩展程序监听的事件。分发这样的事件时,将加载扩展程序的事件页面。相反,如果应用或扩展程序通过调用 removeListener 移除所有的监听器,Chrome 浏览器不会再为那一事件加载其事件页面。

因为监听器本身只在事件页面的环境中存在,您必须每次在事件页面加载时使用 addListener,仅仅在 runtime.onInstalled 这么做是不够的。

有关事件注册操作的具体例子,您可以查看Google Mail Checker扩展程序。

将后台页面转换为事件页面

请根据下列清单,将您的扩展程序的(持久)后台网页转换为事件页面。

  1. 向您的清单文件添加 "persistent": false,如上所示。
  2. 如果您的扩展程序使用 window.setTimeout()window.setInterval(),请改用定时器 API。如果事件页面已关闭,基于 DOM 的定时器不会触发。
  3. 类似地,其他异步 HTML5 API,例如通知与地理定位,在事件页面关闭后不能完成。请改用等价的扩展程序 API,例如通知
  4. 如果您的扩展程序使用 extension.getBackgroundPage,请改用 runtime.getBackgroundPage。新方法是异步的,所以如果有必要的话它可以在返回前启动事件页面。

使用事件页面时的最佳做法

使用事件页面时请牢记这些技巧,避免一些常见而又微妙的陷阱。

  1. 每次事件页面加载时注册您的扩展程序感兴趣的事件。每次您的扩展程序升级到新版本时,事件页面都会加载一次,之后只有当传递您已注册的事件时才会加载。大体上,这意味着您的事件监听器应该在事件页面的顶层区域添加,否则事件页面重新载入时它们不一定可用。
  2. 如果您的扩展程序安装或升级时需要做一些初始化,请监听 runtime.onInstalled 事件。这里很适合注册声明式网络请求规则、右键菜单项以及其他类似的一次性初始化。
  3. 如果您需要在浏览器会话间保持运行时状态,请使用存储 API 或 IndexedDB。由于事件页面不会长时间保持加载状态,您不能再依赖全局变量来保存运行时状态。
  4. 使用事件过滤器将事件通知限制为您关心的那些。例如,如果您监听 tabs.onUpdated 事件,尝试改用 webNavigation.onCompleted 事件并使用过滤器(标签页 API 不支持过滤器),这样,您的事件页面仅在您感兴趣的事件产生时才会加载。
  5. 如果您在事件页面卸载之前需要做最后的清理,请监听 runtime.onSuspend 事件。然而,我们建议您定期保存数据,这样如果您的扩展程序由于崩溃而没有接收到 onSuspend 事件时,一般情况下也不会丢失数据。
  6. 如果您使用消息传递,务必关闭不再使用的端口。在所有消息端口都关闭前,事件页面不会卸载。
  7. 如果您使用右键菜单 API,请向 contextMenus.create 传递一个字符串的 id参数,并使用 contextMenus.onClicked 回调函数代替 contextMenus.createonclick 参数。
  8. 记得测试您的事件页面在卸载和重新载入时能正常工作,这只会在几秒钟不活动后发生。常见的错误包括在网页载入时进行不必要的工作(只应该在扩展程序安装时进行),在网页载入时设置定时器(会重置原来的定时器)以及没有在网页载入时添加事件监听器。