Javascript 使用Port&;从Background.js到content.js;长寿命消息
我已经使用Javascript 使用Port&;从Background.js到content.js;长寿命消息,javascript,google-chrome-extension,Javascript,Google Chrome Extension,我已经使用chrome.runtime.onMessage.addListener完成了从background.js向content.js发送一条消息,但是我需要在扩展生命周期中发送大量消息,因此我需要打开一个端口并使用长期消息 但是,我找不到任何在background.js文件和content.js文件之间打开端口和发送消息/对象的工作示例。有没有人有一个合适的例子 在官方文档“Unchecked runtime.lastError:无法建立连接。接收端不存在”中尝试该示例时,我也遇到了以下问
chrome.runtime.onMessage.addListener
完成了从background.js向content.js发送一条消息,但是我需要在扩展生命周期中发送大量消息,因此我需要打开一个端口并使用长期消息
但是,我找不到任何在background.js文件和content.js文件之间打开端口和发送消息/对象的工作示例。有没有人有一个合适的例子
在官方文档“Unchecked runtime.lastError:无法建立连接。接收端不存在”中尝试该示例时,我也遇到了以下问题。
如果您能在background.js和content.js文件之间提供一个现代的“长寿命消息传递”示例,我们将不胜感激:D
根据要求,这里是我目前正在使用的代码,用于单消息发送。我只是想改变一下,这样我可以发送很多信息,而不是一条
// Content.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message == 'dataready') {
//Do something
sendResponse({});
return true;
}
}
);
// Background.js
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {
message: 'dataready',
action: dataForiFrame
},
function(response) {
});
});
}
});
除非每秒发送数百条消息,否则可能不需要使用基于端口的消息传递,但让我们看看它的外观 您的设置相对复杂,因此需要维护选项卡ID到
端口的映射关系
在内容脚本中启动握手
内容脚本将启动chrome.runtime.connect,后台脚本将监听onConnect并更新映射。然后tabs.onUpdated listener将使用此映射将消息发送到正确的端口
内容脚本:
const port = chrome.runtime.connect({name: 'content'});
port.onMessage.addListener(msg => {
console.log(msg.data);
// send a response if needed, may be a simple object/array
port.postMessage({id: msg.id, data: 'gotcha'});
});
chrome.runtime.onConnect.addListener(port => {
port.onMessage.addListener(msg => {
console.log(msg.data);
// send a response if needed, may be a simple object/array
port.postMessage({id: msg.id, data: 'gotcha'});
});
});
背景脚本:
const portMap = new Map();
const resolveMap = new Map();
let messageId = 0;
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
const response = await send(tabId, {message: 'dataready', action: 'foo'});
console.log(response);
}
});
chrome.runtime.onConnect.addListener(port => {
portMap.set(port.sender.tab.id, port);
port.onDisconnect.addListener(onPortDisconnected);
port.onMessage.addListener(onPortMessage);
});
function onPortDisconnected(port) {
portMap.delete(port.sender.tab.id);
}
function onPortMessage(msg, port) {
resolveMap.get(msg.id)(msg.data);
resolveMap.delete(msg.id);
}
function send(tabId, data) {
return new Promise(resolve => {
const id = ++messageId;
resolveMap.set(id, resolve);
portMap.get(tabId).postMessage({id, data});
});
}
const portMap = new Map();
const resolveMap = new Map();
let messageId = 0;
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
const response = await send(tabId, {message: 'dataready', action: 'foo'});
console.log(response);
}
});
function onPortDisconnected(port) {
portMap.delete(port.sender.tab.id);
}
function onPortMessage(msg, port) {
resolveMap.get(msg.id)(msg.data);
resolveMap.delete(msg.id);
}
function send(tabId, data) {
return new Promise(resolve => {
const id = ++messageId;
let port = portMap.get(tabId);
if (!port) {
port = chrome.tabs.connect(tabId, {frameId: 0});
port.onDisconnect.addListener(onPortDisconnected);
port.onMessage.addListener(onPortMessage);
portMap.set(tabId, port);
}
resolveMap.set(id, resolve);
port.postMessage({id, data});
});
}
这是一个没有任何错误检查的简单示例。还要注意的是,这不是唯一或最好的解决方案。根据问题中不存在的其他因素,可能还有其他解决方案
在后台脚本中启动握手
例如,可以反转握手并在后台脚本中调用chrome.tabs.connect以连接到内容脚本中的onConnect
内容脚本:
const port = chrome.runtime.connect({name: 'content'});
port.onMessage.addListener(msg => {
console.log(msg.data);
// send a response if needed, may be a simple object/array
port.postMessage({id: msg.id, data: 'gotcha'});
});
chrome.runtime.onConnect.addListener(port => {
port.onMessage.addListener(msg => {
console.log(msg.data);
// send a response if needed, may be a simple object/array
port.postMessage({id: msg.id, data: 'gotcha'});
});
});
背景脚本:
const portMap = new Map();
const resolveMap = new Map();
let messageId = 0;
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
const response = await send(tabId, {message: 'dataready', action: 'foo'});
console.log(response);
}
});
chrome.runtime.onConnect.addListener(port => {
portMap.set(port.sender.tab.id, port);
port.onDisconnect.addListener(onPortDisconnected);
port.onMessage.addListener(onPortMessage);
});
function onPortDisconnected(port) {
portMap.delete(port.sender.tab.id);
}
function onPortMessage(msg, port) {
resolveMap.get(msg.id)(msg.data);
resolveMap.delete(msg.id);
}
function send(tabId, data) {
return new Promise(resolve => {
const id = ++messageId;
resolveMap.set(id, resolve);
portMap.get(tabId).postMessage({id, data});
});
}
const portMap = new Map();
const resolveMap = new Map();
let messageId = 0;
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
const response = await send(tabId, {message: 'dataready', action: 'foo'});
console.log(response);
}
});
function onPortDisconnected(port) {
portMap.delete(port.sender.tab.id);
}
function onPortMessage(msg, port) {
resolveMap.get(msg.id)(msg.data);
resolveMap.delete(msg.id);
}
function send(tabId, data) {
return new Promise(resolve => {
const id = ++messageId;
let port = portMap.get(tabId);
if (!port) {
port = chrome.tabs.connect(tabId, {frameId: 0});
port.onDisconnect.addListener(onPortDisconnected);
port.onMessage.addListener(onPortMessage);
portMap.set(tabId, port);
}
resolveMap.set(id, resolve);
port.postMessage({id, data});
});
}
另外,例子的问题是,人们往往在不理解力学的情况下复制它们。例如,您的代码似乎不必要地在未更新的侦听器中使用chrome.tabs.query,即使它已经有了tabId
参数,因此假设它总是活动的选项卡,即使它不是这样更新的。在没有看到当前代码的情况下,不清楚问题是什么。根据扩展的总体工作流程,有许多方法可以组织交流,示例应该很容易找到。至于“Receiving end”错误,它意味着您在另一端没有侦听器的情况下进行连接,这可能是由于多种原因造成的,而且没有太模糊(可能是您的代码错误或manifest.json错误,或者您在重新加载扩展后没有重新加载选项卡)。。我可以更新上面的代码来显示我当前使用的代码,但是正如我所说的,它只适用于发送一条消息。我需要发送多条消息。我发现的例子根本无法使用,因此我在这里发布的原因是:)你看过Chrome的特写吗。他们可能有一个样本会有所帮助。谢谢@wOxxOm,明天晚上我会仔细看看代码。我使用“onUpdated listener”仅在所有内容都已加载并准备就绪时才将消息发送到content.js,否则会出现可怕的“Unchecked runtime.lastError:无法建立连接”。接收端不存在。问题。我真的没有复制和粘贴这些东西,这几乎是半天尝试的结果:DIt仍然在做错误的事情,以防更新不活动的选项卡。这个错误并不是通过这个来“解决”的。该错误意味着在发送消息时没有侦听器,因此很可能是在发送消息后您的内容脚本正在运行。您可以在manifest.json中添加“run_at”:“document_start”
,或者切换到编程注入,在中添加更多信息。我实际上意识到我犯了一个巨大的错误,将其中一个事件侦听器放在了一个函数中,该函数被多次调用,因此产生了很多事件侦听器!所以,我现在有它与我的原始脚本工作!不过,非常感谢您的回答,我会把它标记为正确的:D