Chrome扩展background发消息报「接收端不存在」问题及解决方案咨询
报错根因
Could not establish connection. Receiving end does not exist错误的触发原因确实是popup运行周期限制:popup仅在用户点击扩展图标唤起时处于激活状态,关闭后进程直接销毁,不存在活跃的消息监听器,因此background发送的消息没有接收端。
需求落地方案
1. 定时更新元数据并本地存储
Manifest V3的Service Worker环境无需借助其他脚本即可实现本地存储,直接使用Chrome扩展原生的chrome.storage API即可,该API支持跨上下文读写,权限配置和用法如下:
- 首先在manifest.json中添加权限声明:
{ "permissions": ["storage", "alarms"] }
- background.js中写入下载的元数据示例:
// 闹钟触发下载元数据后存储 chrome.storage.local.set({ translateMeta: 你下载得到的元数据JSON, updateTime: Date.now() }, () => { console.log('元数据存储完成') })
- 其他上下文(popup/内容脚本/offscreen)读取示例:
chrome.storage.local.get("translateMeta", (res) => { const meta = res.translateMeta || {} // 后续业务逻辑 })
2. 后台执行DOM解析、创建标签页等操作
无需依赖popup实现,通过Chrome V3新增的Offscreen Document能力即可满足无目标tab场景下的DOM操作需求,该API专门用于弥补Service Worker无DOM环境的缺陷,默认后台运行不会被随意中断:
- 首先在manifest.json中补充权限:
{ "permissions": ["offscreen", "tabs"] }
- 新增offscreen.html入口文件,引入逻辑脚本offscreen.js:
<!DOCTYPE html> <html> <body> <script src="offscreen.js"></script> </body> </html>
- background.js中先封装Offscreen实例保证唯一性,避免重复创建:
async function getOffscreenInstance() { const existing = await chrome.runtime.getContexts({ contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT] }) if (existing.length) return await chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: [chrome.offscreen.Reason.DOM_PARSER], justification: '解析页面源码、处理DOM相关计算逻辑' }) }
- 页面源码解析逻辑:background下载源码后传递给Offscreen处理即可
// background中下载源码 async function parsePageSource(url) { await getOffscreenInstance() const html = await fetch(url).then(r => r.text()) // 发送给offscreen解析DOM chrome.runtime.sendMessage({ type: 'parseHtml', data: html }, (res) => { console.log('解析结果', res) }) }
- offscreen.js中写监听逻辑处理DOM操作:
chrome.runtime.onMessage.addListener((msg, sender, reply) => { if (msg.type === 'parseHtml') { const dom = new DOMParser().parseFromString(msg.data, 'text/html') // 你的DOM解析逻辑 const result = { title: dom.title, // 其他提取的字段 } reply(result) } })
- 创建新标签页可直接在background中调用API实现,无需迁到popup:
// background中直接调用 chrome.tabs.create({ url: '目标页面地址', active: false // 设为false则后台打开不打断用户操作 }, (newTab) => { // 可拿到新tabID做后续操作 })
补充消息通信兼容逻辑
如果确实需要给popup发送消息,发送前先判断popup是否处于激活状态,未激活则将数据暂存到storage,popup唤起后主动读取即可:
// background中发送前判断 async function sendMsgToPopup(data) { const popupCtx = await chrome.runtime.getContexts({ contextTypes: [chrome.runtime.ContextType.POPUP] }) if (popupCtx.length) { chrome.runtime.sendMessage(data) } else { await chrome.storage.local.set({pendingMsg: data}) } } // popup初始化时读取暂存消息 chrome.storage.local.get("pendingMsg", (res) => { if (res.pendingMsg) { // 处理暂存消息 chrome.storage.local.remove("pendingMsg") } })
内容的提问来源于stack exchange,提问作者Laurent
相关产品推荐
相关产品推荐

