Background:扩展的后台大脑
本教程共 45 篇 · 第 10 篇 · 更新于 2026-08-13 · 约 3 分钟阅读
本节目标:认识后台入口与 defineBackground,理解 MV3 service worker 与 MV2 后台页的差异,掌握「薄入口」原则和 worker 休眠带来的内存陷阱。
后台是什么
background 是扩展的后台大脑:扩展一启动它就在,负责集中监听浏览器事件、协调各环境的消息(消息通信见 §17)、处理需要长期运行的任务。
WXT 里创建它:
// entrypoints/background.ts
export default defineBackground(() => {
// 后台加载时执行
});
也可以带配置对象:
export default defineBackground({
type: 'module', // 使用 ES module
persistent: false, // MV2 下是否常驻
main() {
// 后台加载时执行,不能是 async
},
});
MV3 的 service worker 与 MV2 的后台页
后台入口在两种 manifest 版本下形态不同:
- MV3:编译成 service worker。事件驱动,空闲就睡,浏览器自动管理;
- MV2:编译成后台页(background page)。常驻内存,一直活着。
WXT 按目标版本自动生成对应配置,你通常不用操心。但两种形态的行为差异直接决定代码写法,下面三条规则请记牢。
规则一:main 不能是 async
WXT 构建时会在 Node 环境导入入口文件来读取配置。因此入口文件顶层的运行时代码一律不行——包括顶层调用浏览器 API、顶层操作 DOM。所有运行时逻辑必须放进 main(内容脚本、未列出脚本同理,原理如 §06 所述):
// ❌ 顶层就调用浏览器 API
browser.action.onClicked.addListener(() => {});
// ✅ 放进 main
export default defineBackground(() => {
browser.action.onClicked.addListener(() => {});
});
main 本身也不能标记 async。需要异步时,在 main 内部再开异步函数。
规则二:薄入口,只注册监听
后台最常见的坏味道:main 里塞几百行业务逻辑。正确姿势是 main 只做「注册」,逻辑抽到 lib 模块。看 mkext 的后台入口,整个 main 只有两行消息监听:
// entrypoints/background/index.ts(简化)
export default defineBackground(() => {
onMessage(Message.USER, () => userStore.getValue());
onMessage(Message.DOMAIN_RATINGS, ({ data: domains }) =>
readRatings(domains),
);
});
真正的请求合并、缓存、超时处理都在 readRatings 等函数里。main 薄,worker 重启快,逻辑也好测。
规则三:worker 会休眠,内存不持久
MV3 的 service worker 空闲约 30 秒没有事件,就会被浏览器终止(联网补充:https://mv3-extension.com/manifest-v3-architecture-extension-lifecycle/service-worker-fundamentals )。醒来后一切从头开始——内存里的变量全部丢失。
后果很直接:别把状态只放在后台内存里。要么用 chrome.storage 这类持久存储(如 §18 所述),要么接受「缓存丢失、重新计算」的事实。
mkext 在代码评审中专门记过两条教训:
- 内存缓存必须设上限。Firefox MV2 后台页常驻,缓存不清会无限增长,最后给缓存加了
MAX_CACHE_ENTRIES = 500做 FIFO 淘汰; - 请求超时、并发、失败处理都要写进后台逻辑,不能依赖 worker 常驻兜底。
写缓存、会话、计数这类状态前,先问一句:worker 睡一觉回来,这数据还在吗?不在,就放存储。
最小后台示例
一个只监听安装事件的最小后台:
export default defineBackground(() => {
browser.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
console.log('首次安装');
}
});
});
配合 §08 的「无弹窗 action」,browser.action.onClicked 的监听也写在这里:点图标、查状态、开页面,都从后台统一调度。
什么时候不该用后台
后台不是越重越好。能在内容脚本或页面里完成的事,别绕到后台:每多一次跨环境通信,就多一层序列化和出错面。后台适合的是「全局职责」——事件监听、跨页面协调、需要常驻的缓存。判断标准很简单:这件事是不是整个扩展都依赖的?不是,就放回离它最近的环境。
小结
- 后台是扩展的调度中心:薄入口只注册监听,业务逻辑抽到 lib。
- 浏览器 API 只能放进
main,顶层调用会报错(原理见 §06)。 - MV3 的 worker 会休眠,长期状态进 storage(§18),别指望内存。