Chrome扩展Manifest V3:popup与content脚本通信报错排查
Chrome扩展Manifest V3消息通信错误排查
错误现象
开发基于Manifest V3的Chrome扩展时,点击popup中的按钮偶尔触发以下错误:
Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.
错误触发在调用chrome.tabs.sendMessage向content脚本发送消息的代码行。
相关代码
popup.js
const sendStartSignal = document.getElementById("start-timer"); sendStartSignal.onclick = async function (e) { ... // Get the current tab let tab = await getCurrentTab() // only send a message if you watching a youtube video if(typeof tab !== 'undefined' && tab.url.includes("youtube.com/watch")){ const response = await chrome.tabs.sendMessage( tab.id, { workTime: workTime, restTime: restTime, } ); } else{ console.error("No youtube video on tab.") } };// ERROR SHOWS IT HAPPENING ON THIS LINE async function getCurrentTab() { let queryOptions = { active: true, lastFocusedWindow: true }; // `tab` will either be a `tabs.Tab` instance or `undefined`. let [tab] = await chrome.tabs.query(queryOptions); return tab; }
content.js
chrome.runtime.onMessage.addListener( function (request, sender, sendResponse){ sendResponse({status: "recieved tab with YouTube video"}); startTimer(document.querySelector('video'), request.workTime, request.restTime); }); function startTimer(video, workTime, restTime) { ... const intervalId = setInterval(() => { ... }, 1000); }
Manifest配置片段
"permissions": [ "scripting", "activeTab", "tabs", ], "content_scripts": [ { "js": ["./scripts/content.js"], "matches": ["*://*.youtube.com/watch*"] } ]
问题解答
是否存在未捕获的Promise?
是,未捕获的Promise出现在chrome.tabs.sendMessage的调用位置。
原因分析
chrome.tabs.sendMessage是异步方法,返回一个Promise。当接收端(content脚本)不存在时,这个Promise会被reject,但代码里没有用try/catch包裹该异步调用,导致rejected的Promise未被捕获,从而抛出Uncaught (in promise)错误。- 接收端偶尔不存在的场景:
- YouTube页面刚加载完成,content脚本还未完成注入;
- YouTube是单页应用(SPA),页面通过路由跳转时,content脚本不会自动重新注入,导致接收端丢失;
- 标签页URL匹配但实际页面状态未加载完成,content脚本未初始化。
修复建议
- 用
try/catch捕获消息发送失败的情况,还可以尝试重新注入content脚本后重试:
if(typeof tab !== 'undefined' && tab.url.includes("youtube.com/watch")){ try { const response = await chrome.tabs.sendMessage( tab.id, { workTime: workTime, restTime: restTime } ); } catch (err) { console.error("消息发送失败:", err); // 尝试重新注入content脚本 await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ["./scripts/content.js"] }); // 重新发送消息 const response = await chrome.tabs.sendMessage(tab.id, { workTime, restTime }); } }
- 优化content脚本注入时机:在Manifest的content_scripts配置中添加
"run_at": "document_idle"(默认值)或"document_start",确保脚本在合适时机注入; - 针对SPA路由变化:在content脚本中监听
popstate事件或YouTube自身的路由变化事件,确保消息监听始终有效。
内容的提问来源于stack exchange,提问作者Brice Brown
相关产品推荐
相关产品推荐

