【问题标题】:Chrome extension: How to remove orphaned script after chrom extension updateChrome 扩展程序:如何在 chrome 扩展程序更新后删除孤立的脚本
【发布时间】:2019-12-19 10:45:25
【问题描述】:

我有一个带有弹出页面的 chrome 扩展,它通过简单的一次性请求将布尔变量传递给我的内容页面。然后,内容页面将根据从弹出页面传递的布尔变量的状态执行一些操作。在我不小心删除了扩展程序(仍处于开发人员模式,扩展程序已解压缩)并不得不重新加载它之前,这一直运行良好。

这导致弹出检查控制台中出现扩展上下文无效错误,并且网页控制台似乎验证了弹出页面和内容脚本没有通信。启用 chrome 扩展程序的网页显示以下错误:Unchecked runtime.lastError: The message port closed before a response was received

根据我已经看到的一些答案,似乎重新加载我的 chrome 扩展程序已经从我的扩展程序的其余部分“孤立”了我的原始工作内容脚本,这导致了前面提到的“Unchecked runtime.lastError: The message port在收到回复之前关闭。”网页控制台出错。

我相信我不能只是再次重新注入我的内容脚本,因为我的内容脚本有 DOM 事件侦听器。有没有可能删除当前正在运行的孤立脚本的方法?或者有什么解决这个问题的建议?

这是我的 popup.js:

chrome.tabs.query({'active': true, 'currentWindow': true}, function (tabs) {
    chrome.tabs.sendMessage(tabs[0].id, {cTabSettings: (some boolean variable)});
});

这是我的 content.js:

// Listening for message from popup.js
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.cTabSettings === true) {
      enabled = true;
    } else if (request.cTabSettings === false) {
      enabled = false;
    }
});

// DOM listener and action
document.addEventListener('mousemove', function (e) {
   // Some action
   chrome.runtime.sendMessage({sender: "content", selText : "blah"}, function () {
      console.log("success");
   });
}, false);

我使用的是 chrome 开发者模式版本 76。只是换个说法,这个 chrome 扩展正在工作(内容脚本与弹出窗口通信),然后我意外地重新加载了它。

【问题讨论】:

    标签: javascript google-chrome google-chrome-extension


    【解决方案1】:

    由于孤立的内容脚本仍然可以接收 DOM 消息,例如,通过 window 从您的新工作内容脚本发送一条到幻影内容脚本。收到消息后,您将取消注册所有侦听器(并取消所有全局变量),这也将使您的旧脚本符合自动垃圾收集的条件。

    content.js:

    var orphanMessageId = chrome.runtime.id + 'orphanCheck';
    window.dispatchEvent(new Event(orphanMessageId));
    window.addEventListener(orphanMessageId, unregisterOrphan);
    
    // register all listeners with named functions to preserve their object reference
    chrome.runtime.onMessage.addListener(onMessage);
    document.addEventListener('mousemove', onMouseMove);
    
    // the popup script checks it to see if a usable instance of content script is running
    window.running = true;
    
    function unregisterOrphan() {
      if (chrome.i18n) {
        // someone tried to kick us out but we're not orphaned! 
        return;
      }
      window.removeEventListener(orphanMessageId, unregisterOrphan);
      document.removeEventListener('mousemove', onMouseMove);
      try {
        // 'try' is needed to avoid an exception being thrown in some cases 
        chrome.runtime.onMessage.removeListener(onMessage);
      } catch (e) {}
      return true;
    });
    
    function onMessage(msg, sender, sendResponse) {
      //...........
    }
    
    function onMouseMove(event) {
      // DOM events still fire in the orphaned content script after the extension
      // was disabled/removed and before it's re-enabled or re-installed
      if (unregisterOrphan()) { return }
      //...........
    }
    

    我假设 popup.html 会加载 WebExtension browser API polyfill,因为它允许我们使用 async/await 语法而不是令人难以置信的回调地狱,从而使生活变得更加轻松。

    <script src="browser-polyfill.min.js"></script>
    

    popup.js 应确保在发送消息之前注入内容脚本:

    async function sendMessage(data) {
      const [tab] = await browser.tabs.query({active: true, currentWindow: true});
      if (await ensureContentScript(tab.id)) {
        return await browser.tabs.sendMessage(tab.id, data);
      }
    }
    
    async function ensureContentScript(tabId) {
      try {
        const [running] = await browser.tabs.executeScript(tabId, {
          code: 'window.running === true',
        });
        if (!running) {
          await browser.tabs.executeScript(tabId, {file: 'content.js'});
        }
        return true;
      } catch (e) {}
    }
    

    【讨论】:

      【解决方案2】:

      请查看this answer

      这不是关于删除脚本,而是为了避免错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-18
        • 2013-01-19
        • 2016-08-16
        相关资源
        最近更新 更多