runtime.onMessage
使用此事件监听来自扩展程序其他部分的消息。
一些示例用例包括
要发送由onMessage()
监听器接收的消息,请使用runtime.sendMessage()
或(要发送消息到内容脚本)tabs.sendMessage()
。
注意:避免为相同类型的消息创建多个onMessage()
监听器,因为无法保证多个监听器触发的顺序。
如果要保证消息传递到特定的终点,请使用基于连接的消息交换方法。
除了消息本身之外,监听器还会传递
- 一个
sender
对象,提供有关消息发送者的详细信息。 - 一个
sendResponse()
函数,可用于向发送者发送回复。
您可以通过在监听器内部调用sendResponse()
函数向消息发送同步回复。查看示例。
要发送异步响应,有两种选择
- 从事件监听器返回
true
。这会在监听器返回后使sendResponse()
函数保持有效,以便以后可以调用它。查看示例。警告:不要在函数前面添加
async
。添加async
会将含义更改为使用 Promise 发送异步响应,这与sendResponse(true)
的效果相同。 - 从事件监听器返回一个
Promise
,并在准备好响应时解析(或在发生错误时拒绝它)。查看示例。
注意:您还可以使用基于连接的消息交换方法。
语法
browser.runtime.onMessage.addListener(listener)
browser.runtime.onMessage.removeListener(listener)
browser.runtime.onMessage.hasListener(listener)
事件具有三个函数
addListener(listener)
-
为该事件添加监听器。
removeListener(listener)
-
停止监听此事件。
listener
参数是要移除的监听器。 hasListener(listener)
-
检查是否为此事件注册了至少一个监听器。如果正在监听,则返回
true
,否则返回false
。
addListener 语法
参数
listener
-
发生此事件时调用的函数。该函数传递以下参数
message
-
object
。消息本身。这是一个可序列化的对象(请参阅数据克隆算法)。 sender
-
一个表示消息发送者的
runtime.MessageSender
对象。 sendResponse
-
一个最多可调用一次的函数,用于向
message
发送回复。该函数采用一个参数,该参数可以是任何可序列化的对象(请参阅数据克隆算法)。此参数将传递回消息发送者。如果在同一文档中有多个
onMessage()
监听器,则只能有一个监听器发送回复。要同步发送回复,请在监听器函数返回之前调用
sendResponse()
。要异步发送回复
- 或者保留对
sendResponse()
参数的引用,并从监听器函数返回true
。然后,您可以在监听器函数返回后调用sendResponse()
。 - 或者从监听器函数返回一个
Promise
,并在响应准备就绪时解析该 Promise。这是首选方法。注意:在Chrome 错误 1185241解决之前,Chrome 不支持将 Promise 作为返回值。作为替代方案,返回 true 并使用 sendResponse。
- 或者保留对
listener
函数可以返回布尔值或Promise
。注意:如果将异步函数传递给
addListener()
,则监听器将为其接收的每条消息返回一个 Promise,从而阻止其他监听器响应js// don't do this browser.runtime.onMessage.addListener(async (data, sender) => { if (data.type === "handle_me") { return "done"; } });
如果只想让监听器响应特定类型的消息,则必须将监听器定义为非
async
函数,并且仅为监听器旨在响应的消息返回 Promise — 否则返回 false 或 undefinedjsbrowser.runtime.onMessage.addListener((data, sender) => { if (data.type === "handle_me") { return Promise.resolve("done"); } return false; });
浏览器兼容性
BCD 表仅在浏览器中加载
示例
简单示例
此内容脚本监听网页上的点击事件。如果点击的是链接,则会向后台页面发送目标 URL 消息
// content-script.js
window.addEventListener("click", notifyExtension);
function notifyExtension(e) {
if (e.target.tagName !== "A") {
return;
}
browser.runtime.sendMessage({ url: e.target.href });
}
后台脚本监听这些消息,并使用notifications
API 显示通知
// background-script.js
browser.runtime.onMessage.addListener(notify);
function notify(message) {
browser.notifications.create({
type: "basic",
iconUrl: browser.extension.getURL("link.png"),
title: "You clicked a link!",
message: message.url,
});
}
发送同步响应
此内容脚本在用户点击页面时向后台脚本发送消息。它还会记录后台脚本发送的任何响应
// content-script.js
function handleResponse(message) {
console.log(`background script sent a response: ${message.response}`);
}
function handleError(error) {
console.log(`Error: ${error}`);
}
function sendMessage(e) {
const sending = browser.runtime.sendMessage({
content: "message from the content script",
});
sending.then(handleResponse, handleError);
}
window.addEventListener("click", sendMessage);
这是一个对应后台脚本的版本,它从监听器内部同步发送响应。
// background-script.js
function handleMessage(request, sender, sendResponse) {
console.log(`content script sent a message: ${request.content}`);
sendResponse({ response: "response from background script" });
}
browser.runtime.onMessage.addListener(handleMessage);
这是一个使用Promise.resolve()
的另一个版本。
// background-script.js
function handleMessage(request, sender, sendResponse) {
console.log(`content script sent a message: ${request.content}`);
return Promise.resolve({ response: "response from background script" });
}
browser.runtime.onMessage.addListener(handleMessage);
使用 sendResponse 发送异步响应
这是前面示例中后台脚本的另一个版本。它在监听器返回后异步发送响应。请注意监听器中的return true;
:这告诉浏览器您打算在监听器返回后使用sendResponse
参数。
// background-script.js
function handleMessage(request, sender, sendResponse) {
console.log(`content script sent a message: ${request.content}`);
setTimeout(() => {
sendResponse({ response: "async response from background script" });
}, 1000);
return true;
}
browser.runtime.onMessage.addListener(handleMessage);
警告:不要在函数前面添加async
。添加async
会将含义更改为使用 Promise 发送异步响应,这与sendResponse(true)
的效果相同。
使用 Promise 发送异步响应
注意:在Chrome 错误 1185241解决之前,Chrome 不支持将 Promise 作为返回值。作为替代方案,返回 true 并使用sendResponse
。
此内容脚本获取页面上的第一个<a>
链接,并发送一条消息询问链接的位置是否已添加书签。它期望获得一个布尔响应(如果位置已添加书签,则为true
,否则为false
)
// content-script.js
const firstLink = document.querySelector("a");
function handleResponse(isBookmarked) {
if (isBookmarked) {
firstLink.classList.add("bookmarked");
}
}
browser.runtime
.sendMessage({
url: firstLink.href,
})
.then(handleResponse);
这是后台脚本。它使用
查看链接是否已添加书签,该函数返回一个bookmarks.search()
Promise
// background-script.js
function isBookmarked(message, sender, response) {
return browser.bookmarks
.search({
url: message.url,
})
.then((results) => results.length > 0);
}
browser.runtime.onMessage.addListener(isBookmarked);
如果异步处理程序不返回 Promise,您可以显式构造一个 Promise。这个相当牵强的例子使用setTimeout()
在 1 秒延迟后发送响应。
// background-script.js
function handleMessage(request, sender, sendResponse) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ response: "async response from background script" });
}, 1000);
});
}
browser.runtime.onMessage.addListener(handleMessage);
扩展示例
注意:此 API 基于 Chromium 的chrome.runtime
API。本文档源自 Chromium 代码中的runtime.json
。