使用 Service Worker 管理事件
扩展程序是基于事件的程序,用于修改或增强 Chrome 浏览体验。事件是浏览器触发器,例如导航到新页面、移除书签或关闭选项卡。扩展使用后台服务工作线程中的脚本监控这些事件,然后响应指定的指令。
后台服务工作者在需要时加载,并在空闲时卸载。一些事件示例包括:
- 扩展程序首先安装或更新到新版本。
- 后台页面正在侦听一个事件,并且该事件被调度。
- 内容脚本或其他扩展程序发送消息。
- 扩展中的另一个视图(例如弹出窗口)调用
runtime.getBackgroundPage
。
加载完成后,只要 Service Worker 正在执行操作(例如调用 Chrome API 或发出网络请求),它就会一直运行。此外,在所有可见视图和所有消息端口都关闭之前,Service Worker 不会卸载。
打开视图不会导致 service worker 加载,但只会阻止它在加载后关闭。
有效的后台脚本会一直处于休眠状态,直到它们监听的事件发生,对指定的指令做出反应,然后卸载。
# 注册后台脚本(Register background scripts)
扩展在“background
”字段下的清单中注册其后台服务工作者。此字段使用“service_worker
”键,该键指定单个 JavaScript 文件。
{
"name": "Awesome Test Extension",
...
"background": {
"service_worker": "background.js"
},
...
}
用于“service_worker”的脚本必须位于扩展的根目录中。
您可以选择指定一个额外的 "type": "module"
字段以将 service worker
作为 ES
模块包含在内,这允许您导入更多代码。有关更多信息,请参阅 Service Worker 中的 ES 模块。例如:
"background": {
"service_worker": "background.js",
"type": "module"
}
# 初始化扩展(Initialize the extension)
侦听 runtime.onInstalled 事件以在安装时初始化扩展。使用此事件设置状态或一次性初始化,例如上下文菜单。
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
"id": "sampleContextMenu",
"title": "Sample Context Menu",
"contexts": ["selection"]
});
});
# 设置监听器(Set up listeners)
围绕扩展所依赖的事件构建后台脚本。定义功能相关的事件允许后台脚本处于休眠状态,直到这些事件被触发并防止扩展丢失重要的触发器。
监听器必须从页面开始同步注册。
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
"id": "sampleContextMenu",
"title": "Sample Context Menu",
"contexts": ["selection"],
});
});
// This will run when a bookmark is created.
chrome.bookmarks.onCreated.addListener(() => {
// do something
});
不要异步注册侦听器,因为它们不会被正确触发。
chrome.runtime.onInstalled.addListener(() => {
// 错误!事件必须从开始同步注册
// the page.
chrome.bookmarks.onCreated.addListener(() => {
// do something
});
});
扩展可以通过调用 removeListener 从其后台脚本中删除侦听器。如果某个事件的所有侦听器都被删除,Chrome 将不再为该事件加载扩展程序的后台脚本。
chrome.runtime.onMessage.addListener((message, sender, reply) => {
chrome.runtime.onMessage.removeListener(event);
});
# Filter events(过滤事件)
使用支持事件过滤器(event filters)的 API 将侦听器限制为扩展所关心的情况。如果扩展程序正在侦听 tabs.onUpdated
事件,请尝试使用带有过滤器的 webNavigation.onCompleted
事件,因为 tabs API 不支持过滤器。
const filter = {
url: [
{
urlMatches: 'https://www.google.com/',
},
],
};
chrome.webNavigation.onCompleted.addListener(() => {
console.info("The user has loaded my favorite website!");
}, filter);
# 对听众作出反应(React to listeners)
一旦事件被触发,监听器就会触发功能。要对事件做出反应,请在侦听器事件内部构建所需的反应。
chrome.runtime.onMessage.addListener((message, callback) => {
const tabId = getForegroundTabId();
if (message.data === "setAlarm") {
chrome.alarms.create({delayInMinutes: 5})
} else if (message.data === "runLogic") {
chrome.scripting.executeScript({file: 'logic.js', tabId});
} else if (message.data === "changeColor") {
chrome.scripting.executeScript(
{func: () => document.body.style.backgroundColor="orange", tabId});
};
});
# Unload background scripts(卸载后台脚本)
数据应该定期保存,这样如果扩展程序崩溃而没有收到 onSuspend,重要信息就不会丢失。使用存储(storage) API 来帮助解决这个问题。
chrome.storage.local.set({variable: variableInformation});
如果扩展程序使用消息传递(message passing),请确保关闭所有端口。在所有消息端口都关闭之前,后台脚本不会卸载。侦听 runtime.Port.onDisconnect
事件将深入了解开放端口何时关闭。使用 runtime.Port.disconnect
手动关闭它们。
chrome.runtime.onMessage.addListener((message, callback) => {
if (message === 'hello') {
sendResponse({greeting: 'welcome!'})
} else if (message === 'goodbye') {
chrome.runtime.Port.disconnect();
}
});
后台服务工作者的生命周期可以通过监视扩展条目何时出现和从 Chrome 的任务管理器中消失来观察。
通过单击 Chrome 菜单打开任务管理器,将鼠标悬停在更多工具上并选择“任务管理器”。
Service Worker 在几秒钟不活动后自行卸载。如果需要任何最后一分钟的清理,请收听 runtime.onSuspend
事件。
chrome.runtime.onSuspend.addListener(() => {
console.log("Unloading.");
chrome.browserAction.setBadgeText({text: ""});
});
但是,与依赖 runtime.onSuspend
相比,在存储(storage) API 中持久化数据应该是首选。它不允许进行尽可能多的清理,并且在发生崩溃时也无济于事。
By.一粒技术服务.