Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/454.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript chrome.runtime.sendMessage在重新加载chrome扩展后从内容脚本引发异常_Javascript_Google Chrome_Google Chrome Extension_Content Script - Fatal编程技术网

Javascript chrome.runtime.sendMessage在重新加载chrome扩展后从内容脚本引发异常

Javascript chrome.runtime.sendMessage在重新加载chrome扩展后从内容脚本引发异常,javascript,google-chrome,google-chrome-extension,content-script,Javascript,Google Chrome,Google Chrome Extension,Content Script,我将注入内容脚本中的消息发送回Chrome扩展中的后台脚本,如下所示: chrome.runtime.sendMessage({action: "myResult"}); 这很好,直到我重新加载我的扩展(通过进入设置->扩展->“重新加载(Ctrl+R)”来加载扩展) 反过来,当我的后台脚本启动时,它会重复调用所有打开的选项卡的chrome.tabs.executeScript,以编程方式重新注入我的内容脚本(.) 但在我这样做之后,如果我从我的内容脚本中调用第一行sendMessage,它会

我将注入内容脚本中的消息发送回Chrome扩展中的后台脚本,如下所示:

chrome.runtime.sendMessage({action: "myResult"});
这很好,直到我重新加载我的扩展(通过进入设置->扩展->“重新加载(Ctrl+R)”来加载扩展)

反过来,当我的后台脚本启动时,它会重复调用所有打开的选项卡的
chrome.tabs.executeScript
,以编程方式重新注入我的内容脚本(.)

但在我这样做之后,如果我从我的内容脚本中调用第一行
sendMessage
,它会抛出以下异常:

错误:连接到扩展名my_extension_id时出错


知道为什么会发生这种情况吗?

当重新加载扩展运行时,会发生以下任何情况

  • 你打过电话了
  • 您已在
    chrome://extensions/
  • 扩展已更新
然后内容脚本中的大多数扩展API方法停止工作(包括
chrome.runtime.sendMessage
,这会导致问题中的错误)。有两种方法可以解决这个问题

选项1:退回到仅限contentscript的功能 如果您的扩展可以在没有背景页面的情况下完美运行,那么这可能是一个可接受的解决方案。例如,如果您的内容脚本除了修改DOM和/或执行跨源请求外,不做任何其他事情

在从我的内容脚本调用任何Chrome扩展API之前,我在我的一个扩展中使用以下代码片段来检测运行时是否仍然有效

// It turns out that getManifest() returns undefined when the runtime has been
// reload through chrome.runtime.reload() or after an update.
function isValidChromeRuntime() {
    // It turns out that chrome.runtime.getManifest() returns undefined when the
    // runtime has been reloaded.
    // Note: If this detection method ever fails, try to send a message using
    // chrome.runtime.sendMessage. It will throw an error upon failure.
    return chrome.runtime && !!chrome.runtime.getManifest();
}

// E.g.
if (isValidChromeRuntime()) {
    chrome.runtime.sendMessage( ... );
} else {
    // Fall back to contentscript-only behavior
}
选项2:在内容脚本插入时卸载上一个内容脚本 如果与后台页面的连接对内容脚本很重要,则必须执行适当的卸载例程,并设置一些事件,以便在通过插入回以前的内容脚本时卸载以前的内容脚本


请注意,任何知道事件名称的页面都可能触发内容脚本的销毁。这是不可避免的,因为在扩展运行时被破坏之后,就没有合适的方法可以安全地与扩展通信了。

关于主题,请确保两件事:1)您没有从内容脚本的前一个实例中获得这一行,2)在注册一个
onMessage
侦听器之前,您没有注入脚本。@Xan:是的。这不是这个网站的目的吗?很明显,我只在遇到死胡同的时候才努力研究和提问。所以回到你的主题评论。我如何确保#1?我感谢你花时间解释这一点!关于你的选择2,还有一个问题。我在重新加载后开始重新注入内容脚本的原因是,我无法再从后台脚本与它们通信。但如果是这样,我如何让他们知道他们必须卸货?另一方面,无论是内容脚本还是背景脚本本身都无法知道扩展将被卸载以执行您所解释的操作。这个场景不符合catch 22吗?@c0000fd我正在使用一个自定义DOM事件(请参阅代码片段末尾的
main();
之前的最后四行)来管理卸载。首先,我触发定制事件来指示任何侦听器(可能是以前的内容脚本)清理自身。然后我绑定一个新的事件侦听器来侦听该事件。最后,我通过调用
main()
函数来设置内容脚本。所以DOM事件会起作用,哈。好主意,谢谢+1对于发送DOM事件,请不要考虑这个问题。@c00000fd DOM事件可以工作,因为内容脚本实际上只是继续执行,只是切断了父背景页。
// Content script
function main() {
    // Set up content script
}

function destructor() {
    // Destruction is needed only once
    document.removeEventListener(destructionEvent, destructor);
    // Tear down content script: Unbind events, clear timers, restore DOM, etc.
}

var destructionEvent = 'destructmyextension_' + chrome.runtime.id;
// Unload previous content script if needed
document.dispatchEvent(new CustomEvent(destructionEvent));
document.addEventListener(destructionEvent, destructor);
main();