事件页面
应用和扩展程序通常需要长时间运行的脚本来管理某些任务或状态,这就是事件页面的作用。事件页面只在需要时加载,当事件页面不活动时就会卸载,以便释放内存和其他系统资源。
从 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扩展程序。
将后台页面转换为事件页面
请根据下列清单,将您的扩展程序的(持久)后台网页转换为事件页面。
- 向您的清单文件添加
"persistent": false
,如上所示。 -
如果您的扩展程序使用
window.setTimeout()
或window.setInterval()
,请改用定时器 API。如果事件页面已关闭,基于 DOM 的定时器不会触发。 - 类似地,其他异步 HTML5 API,例如通知与地理定位,在事件页面关闭后不能完成。请改用等价的扩展程序 API,例如通知。
-
如果您的扩展程序使用
extension.getBackgroundPage
,请改用runtime.getBackgroundPage
。新方法是异步的,所以如果有必要的话它可以在返回前启动事件页面。
使用事件页面时的最佳做法
使用事件页面时请牢记这些技巧,避免一些常见而又微妙的陷阱。
- 每次事件页面加载时注册您的扩展程序感兴趣的事件。每次您的扩展程序升级到新版本时,事件页面都会加载一次,之后只有当传递您已注册的事件时才会加载。大体上,这意味着您的事件监听器应该在事件页面的顶层区域添加,否则事件页面重新载入时它们不一定可用。
- 如果您的扩展程序安装或升级时需要做一些初始化,请监听 runtime.onInstalled 事件。这里很适合注册声明式网络请求规则、右键菜单项以及其他类似的一次性初始化。
- 如果您需要在浏览器会话间保持运行时状态,请使用存储 API 或 IndexedDB。由于事件页面不会长时间保持加载状态,您不能再依赖全局变量来保存运行时状态。
-
使用事件过滤器将事件通知限制为您关心的那些。例如,如果您监听
tabs.onUpdated
事件,尝试改用webNavigation.onCompleted
事件并使用过滤器(标签页 API 不支持过滤器),这样,您的事件页面仅在您感兴趣的事件产生时才会加载。 - 如果您在事件页面卸载之前需要做最后的清理,请监听
runtime.onSuspend
事件。然而,我们建议您定期保存数据,这样如果您的扩展程序由于崩溃而没有接收到onSuspend
事件时,一般情况下也不会丢失数据。 - 如果您使用消息传递,务必关闭不再使用的端口。在所有消息端口都关闭前,事件页面不会卸载。
-
如果您使用右键菜单 API,请向
contextMenus.create
传递一个字符串的id
参数,并使用contextMenus.onClicked
回调函数代替contextMenus.create
的onclick
参数。 - 记得测试您的事件页面在卸载和重新载入时能正常工作,这只会在几秒钟不活动后发生。常见的错误包括在网页载入时进行不必要的工作(只应该在扩展程序安装时进行),在网页载入时设置定时器(会重置原来的定时器)以及没有在网页载入时添加事件监听器。