scripting.executeScript:在导致可怕的“接收端不存在”之后立即调用 chrome.tabs.sendMessage。

问题描述 投票:0回答:1

问题

通过

chrome.scripting.executeScript()
注入内容脚本并向选项卡发送消息时,是否有办法解决计时问题?

问题

在此代码中,我将内容脚本注入选项卡,然后向选项卡发送消息。不幸的是,这会引发可怕的

Receiving end does not exist.
问题,除非我添加
setTimeout()
调用,我绝对不想这样做(这样做很容易出现错误)。有什么办法可以让这项工作不超时吗?

chrome.contextMenus.onClicked.addListener(async (onClickData, tab) => {
  await chrome.scripting.executeScript({
    target: { tabId: tab!.id! },
    files: [schedulerScript],
  });

  
  await new Promise((resolve) => setTimeout(resolve, 100)); //<-- "Receiving end does not exist." throw if this isn't here

  await chrome.tabs.sendMessage(tab!.id!, {
    type: "setActiveEditableElement",
  });
  await handleMenuItemClick(onClickData, tab);
});

这是我写入选项卡的脚本内容:

import { handleMessage } from "./messageHandlers";

chrome.runtime.onMessage.addListener(handleMessage);

我所做的尝试

我尝试过使用内容脚本将消息发送回服务工作人员以表明其已准备好,但这非常复杂,服务工作人员 -> 内容脚本 -> 内容脚本将消息发送回服务工作人员 -> 服务工作然后告诉它做某事。这很难维护。

有趣。 在这个问题中看起来建议提供一个返回承诺的函数。这迫使

executeScript()
调用等待承诺解决。值得研究一下。

任何想法都值得赞赏。您是否遇到过脚本处理程序未准备好的计时问题?

google-chrome-extension sendmessage execute-script
1个回答
0
投票

执行脚本+函数

如果第一个操作始终相同,您可以在内容脚本中显式调用它,但是当它不同时,您可以将处理函数设为全局并使用第二个executeScript来调用它:

//内容.js

chrome.runtime.onMessage.addListener(self.onMessage = (msg, sender, sendResponse) => {
  // ........
});

//背景.js

chrome.contextMenus.onClicked.addListener(async (onClickData, tab) => {
  await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ['content.js'],
  });
  await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: () => onMessage({type: 'setActiveEditableElement'}),
    // Note that `sender` and `sendResponse` will be undefined in onMessage
  });
});

内容脚本要求数据

//内容.js

chrome.runtime.onMessage.addListener(self.onMessage = (msg, sender, sendResponse) => {
  // ........
});
chrome.runtime.sendMessage('contentInit').then(onMessage, () => {});
// Note that `sender` and `sendResponse` will be undefined in onMessage

//背景.js

chrome.contextMenus.onClicked.addListener(async (onClickData, tab) => {
  const response = {type: 'setActiveEditableElement'};
  const pr = Promise.withResolvers();
  const onMessage = (msg, sender, sendResponse) => {
    if (msg === 'contentInit' && sender.tab.id === tab.id) {
      chrome.runtime.onMessage.removeListener(onMessage);
      sendResponse(response);
      pr.resolve();
    }
  };
  chrome.runtime.onMessage.addListener(onMessage);
  await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ['content.js'],
  });
  await pr.promise;
});

内容脚本返回以指示准备就绪

//内容.js

chrome.runtime.connect({name: 'onMessage'});
chrome.runtime.onMessage.addListener(....................);

//背景.js

chrome.contextMenus.onClicked.addListener(async (onClickData, tab) => {
  const pr = Promise.withResolvers();
  chrome.runtime.onConnect.addListener(function onConnect(port) {
    if (port.name === 'onMessage' && port.sender.tab.id === tab.id) {
      chrome.runtime.onConnect.removeListener(onConnect);
      port.disconnect();
      pr.resolve();
    }
  });
  await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ['content.js'],
  });
  await pr.promise;
  await chrome.tabs.sendMessage(tab.id, {foo: 'bar'});
});
© www.soinside.com 2019 - 2024. All rights reserved.