Port.postmessage() 中的发送响应
sendResponse in Port.postmessage()
我有以下代码
browser.runtime.onConnect.addListener(function (externalPort) {
externalPort.onMessage.addListener((message, sender, sendResponse) => {
sendResponse(42);
}
});
但是,Port.onMessage
的侦听器似乎不会像 browser.runtime.onMessage
的侦听器那样通过 sendResponse
被调用。
知道如何将消息响应发送到端口吗?
Port.postMessage()
是一种仅推送消息传递方法,因此您需要并行使用常规 runtime.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(port => {
let tabId;
const listenerForPort = (message, sender) => {
if (message &&
typeof message == 'object' &&
message.portName == port.name) {
switch (message.type) {
case 'get-tabId':
return Promise.resolve(tabId);
}
}
};
browser.runtime.onMessage.addListener(listenerForPort);
port.onMessage.addListener(message => {
if (message &&
typeof message == 'object' &&
message.tabId)
tabId = message.tabId;
});
port.onDisconnect.addListener(port => {
browser.runtime.onMessage.removeListener(listenerForPort);
if (tabId)
browser.tabs.remove(tabId);
});
});
panel.html:
<!DOCTYPE html>
<script type="application/javascript" src="panel.js"></script>
<button id="button">Click Me</button>
panel.js:
browser.windows.getCurrent({ populate: true }).then(win => {
const portName = `port for window ${win.id}`;
const activeTab = win.tabs.find(tab => tab.active);
const port = browser.runtime.connect({
name: portName
});
port.postMessage({ tabId: activeTab.id });
const button = document.getElementById('button');
button.addEventListener('click', async event => {
const tabIdFromBackground = await browser.runtime.sendMessage({
type: 'get-tabId',
portName
});
button.textContent = tabIdFromBackground;
});
});
在这个例子中,有一个监听器对应一个连接,它被设计为只响应以相应端口名称发送的消息。
基于端口的消息传递不使用 sendResponse。只需 post 另一个消息到端口。
这是基于端口的消息传递系统的一个非常简化的示例。它不传输错误或异常,没有超时。这个想法是传递一个 id
,将 id 的回调保存在映射中,并在响应中使用相同的 id 来调用保存的回调。
不像 browser.runtime.sendMessage 每次都创建一个新端口(如果您发送大量消息,这是一个相对昂贵的操作),我们会重复使用同一个端口。
发件人:
const port = browser.runtime.connect({name: 'foo'});
const portMap = new Map();
let portMessageId = 0;
port.onMessage.addListener(msg => {
const {id, data} = msg;
const resolve = portMap.get(id);
portMap.delete(id);
resolve(data);
});
function send(data) {
return new Promise(resolve => {
const id = ++portMessageId;
portMap.set(id, resolve);
port.postMessage({id, data});
});
}
用法:
(async () => {
const response = await send({foo: 'whatever'});
console.log(response);
})();
接收者:
/** @param {chrome.runtime.Port} port */
browser.runtime.onConnect.addListener(port => {
if (port.name === 'foo') {
port.onMessage.addListener(msg => {
const {id, data} = msg;
port.postMessage({id, data: processMessage(data)});
});
}
});
我有以下代码
browser.runtime.onConnect.addListener(function (externalPort) {
externalPort.onMessage.addListener((message, sender, sendResponse) => {
sendResponse(42);
}
});
但是,Port.onMessage
的侦听器似乎不会像 browser.runtime.onMessage
的侦听器那样通过 sendResponse
被调用。
知道如何将消息响应发送到端口吗?
Port.postMessage()
是一种仅推送消息传递方法,因此您需要并行使用常规 runtime.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(port => {
let tabId;
const listenerForPort = (message, sender) => {
if (message &&
typeof message == 'object' &&
message.portName == port.name) {
switch (message.type) {
case 'get-tabId':
return Promise.resolve(tabId);
}
}
};
browser.runtime.onMessage.addListener(listenerForPort);
port.onMessage.addListener(message => {
if (message &&
typeof message == 'object' &&
message.tabId)
tabId = message.tabId;
});
port.onDisconnect.addListener(port => {
browser.runtime.onMessage.removeListener(listenerForPort);
if (tabId)
browser.tabs.remove(tabId);
});
});
panel.html:
<!DOCTYPE html>
<script type="application/javascript" src="panel.js"></script>
<button id="button">Click Me</button>
panel.js:
browser.windows.getCurrent({ populate: true }).then(win => {
const portName = `port for window ${win.id}`;
const activeTab = win.tabs.find(tab => tab.active);
const port = browser.runtime.connect({
name: portName
});
port.postMessage({ tabId: activeTab.id });
const button = document.getElementById('button');
button.addEventListener('click', async event => {
const tabIdFromBackground = await browser.runtime.sendMessage({
type: 'get-tabId',
portName
});
button.textContent = tabIdFromBackground;
});
});
在这个例子中,有一个监听器对应一个连接,它被设计为只响应以相应端口名称发送的消息。
基于端口的消息传递不使用 sendResponse。只需 post 另一个消息到端口。
这是基于端口的消息传递系统的一个非常简化的示例。它不传输错误或异常,没有超时。这个想法是传递一个 id
,将 id 的回调保存在映射中,并在响应中使用相同的 id 来调用保存的回调。
不像 browser.runtime.sendMessage 每次都创建一个新端口(如果您发送大量消息,这是一个相对昂贵的操作),我们会重复使用同一个端口。
发件人:
const port = browser.runtime.connect({name: 'foo'});
const portMap = new Map();
let portMessageId = 0;
port.onMessage.addListener(msg => {
const {id, data} = msg;
const resolve = portMap.get(id);
portMap.delete(id);
resolve(data);
});
function send(data) {
return new Promise(resolve => {
const id = ++portMessageId;
portMap.set(id, resolve);
port.postMessage({id, data});
});
}
用法:
(async () => {
const response = await send({foo: 'whatever'});
console.log(response);
})();
接收者:
/** @param {chrome.runtime.Port} port */
browser.runtime.onConnect.addListener(port => {
if (port.name === 'foo') {
port.onMessage.addListener(msg => {
const {id, data} = msg;
port.postMessage({id, data: processMessage(data)});
});
}
});