Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/372.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 使用Port&;从Background.js到content.js;长寿命消息_Javascript_Google Chrome Extension - Fatal编程技术网

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