通过
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()
调用等待承诺解决。值得研究一下。
任何想法都值得赞赏。您是否遇到过脚本处理程序未准备好的计时问题?
如果第一个操作始终相同,您可以在内容脚本中显式调用它,但是当它不同时,您可以将处理函数设为全局并使用第二个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'});
});