Firefox 在Port.postmessage()中发送响应

Firefox 在Port.postmessage()中发送响应,firefox,firefox-addon-webextensions,Firefox,Firefox Addon Webextensions,我有以下代码 browser.runtime.onConnect.addListener(function (externalPort) { externalPort.onMessage.addListener((message, sender, sendResponse) => { sendResponse(42); } }); 但是,Port.onMessage的侦听器似乎不会以sendsresponse作为browser.runtime.onMessa

我有以下代码

browser.runtime.onConnect.addListener(function (externalPort) {
    externalPort.onMessage.addListener((message, sender, sendResponse) => {
      sendResponse(42);
    }
});

但是,
Port.onMessage
的侦听器似乎不会以
sendsresponse
作为
browser.runtime.onMessage
的侦听器调用

知道如何将消息响应发送到端口吗?

端口。postMessage()是一种仅推送的消息传递方法,因此您需要并行使用常规的
运行时.sendMessage()
方法。以下是一个例子:

manifest.json:

{
  "name": "panel example",
  "version": "1",
  "manifest_version": 2,
  "background": {
    "scripts": ["background.js"]
  },
  "browser_action": {
    "default_title": "panel",
    "default_popup": "panel.html"
  },
  "permissions": [
    "tabs"
  ]
}
background.js:

browser.runtime.onConnect.addListener(端口=>{
让塔比德;
常量listenerForPort=(消息,发件人)=>{
如果(信息)&&
消息的类型==“对象”&&
message.portName==端口名){
开关(message.type){
案例“get tabId”:
返回承诺。解决(tabId);
}
}
};
browser.runtime.onMessage.addListener(listenerForPort);
port.onMessage.addListener(消息=>{
如果(信息)&&
消息的类型==“对象”&&
message.tabId)
tabId=message.tabId;
});
port.onDisconnect.addListener(端口=>{
browser.runtime.onMessage.RemovelListener(listenerForPort);
if(tabId)
browser.tabs.remove(tabId);
});
});
panel.html:


点击我
panel.js:

browser.windows.getCurrent({populate:true})。然后(win=>{
const portName=`窗口${win.id}的端口`;
const activeTab=win.tabs.find(tab=>tab.active);
const port=browser.runtime.connect({
名称:端口名
});
port.postMessage({tabId:activeTab.id});
const button=document.getElementById('button');
addEventListener('click',异步事件=>{
const tabIdFromBackground=等待browser.runtime.sendMessage({
键入:“get tabId”,
端口名
});
button.textContent=tabIdFromBackground;
});
});

在本例中,有一个侦听器对应于一个连接,它被设计为只响应使用相应端口名发送的消息。

基于端口的消息不使用sendResponse。只需将另一条消息发送到端口

下面是一个非常简单的基于端口的消息传递系统示例。它不传输错误或异常,没有超时。其思想是传递一个
id
,将id的回调保存在映射中,并在响应中使用相同的id来调用保存的回调

与browser.runtime.sendMessage每次都创建一个新端口不同(如果发送大量消息,这是一个相对昂贵的操作),我们重复使用相同的端口

发件人:

const-port=browser.runtime.connect({name:'foo'});
const portMap=新映射();
让portMessageId=0;
port.onMessage.addListener(msg=>{
const{id,data}=msg;
const resolve=portMap.get(id);
portMap.delete(id);
解析(数据);
});
函数发送(数据){
返回新承诺(解决=>{
const id=++portMessageId;
portMap.set(id,resolve);
port.postMessage({id,data});
});
}
用法:

(异步()=>{
const response=await send({foo:'whatever'});
控制台日志(响应);
})();
接收人:

/**@param{chrome.runtime.Port}Port*/
browser.runtime.onConnect.addListener(端口=>{
如果(port.name==='foo'){
port.onMessage.addListener(msg=>{
const{id,data}=msg;
port.postMessage({id,data:processMessage(data)});
});
}
});

基于端口的消息传递不使用sendResponse。您只需向端口发送另一条消息。查看文档中的示例。FWIW这里是中的示例,唯一的区别是在Firefox中它是
浏览器
,而不是
浏览器
。我明白了。谢谢你的推荐。发送消息并将输出分配给变量的范例是什么?以前我做的是
let retVal=await browser.runtime.sendMessage({type:'getOutput'})然后执行
发送响应(42)。如果我来回发布消息,我不知道如何将值
42
返回给调用者。我希望避免为我需要的每一个输出都使用全局变量。没有必要使用伪值进行响应,所以不要发送任何内容。如果有一个有意义的值,您必须将
id
属性添加到message对象,并使用一个对象或
Map
,将id绑定到postMessage的承诺包装器的
resolve
函数。您应该使用的方法是:性能。当您需要发送大量消息时,
Port.postMessage()
非常有用。
runtime.sendMessage()
Port.postMessage()
慢10倍(或更多/更少),但它很容易返回消息响应。(顺便说一句,如果您基于
端口.postMessage()
构建任何每条消息响应系统,它的速度将与
运行时类似。sendMessage()
)每条消息系统不应该慢,因为唯一的开销是在映射或对象中进行简单的查找,以将
id
解析为启动器的回调函数。sendMessage的速度慢不是因为这个原因,它慢是因为每次都需要创建一个新端口,这是一个相对昂贵的过程。哦,我没有调查为什么会有这样的性能差异。谢谢你的提示。(无论如何,我仍然在我的项目中使用这两种方法,因为我相信标准方法看起来比自定义方法更容易理解。)