runtime.onMessage
使用此事件監聽來自擴充套件程式其他部分的的訊息。
一些示例用例包括:
- 在 內容指令碼 中監聽來自 背景指令碼 的訊息。
- 在背景指令碼中監聽來自內容指令碼的訊息。
- 在 選項頁面或彈出視窗 指令碼中監聽來自背景指令碼的訊息。
- 在背景指令碼中監聽來自選項頁面或彈出視窗指令碼的訊息。
要傳送被 onMessage() 監聽器接收的訊息,請使用 runtime.sendMessage() 或(要將訊息傳送到內容指令碼) tabs.sendMessage()。
注意: 避免為同一型別的訊息建立多個 onMessage() 監聽器,因為多個監聽器觸發的順序不保證。
如果您想確保訊息成功傳遞到特定端點,請使用 基於連線的訊息交換方法。
除了訊息本身,監聽器還會收到
- 一個
sender物件,其中包含有關訊息傳送者的詳細資訊。 - 一個
sendResponse()函式,可用於將響應傳送回傳送者。
您可以透過在監聽器中呼叫 sendResponse() 函式來發送同步響應。請參閱 傳送同步響應示例。
要傳送非同步響應,有兩種選擇:
- 從事件監聽器返回
true。這會使sendResponse()函式在監聽器返回後仍然有效,因此您可以稍後呼叫它。請參閱 使用sendResponse傳送非同步響應示例。警告: 不要將
async新增到函式前面。新增async會改變其含義,使其變為 使用 Promise 傳送非同步響應,這實際上與sendResponse(true)相同。 - 從事件監聽器返回一個
Promise,並在準備好響應時解析(或在出錯時拒絕)。[請參閱 使用 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 語法
引數
監聽器-
此事件發生時呼叫的函式。該函式會傳遞以下引數:
message-
object。訊息。這是一個可序列化的物件(請參閱 資料克隆演算法)。 sender-
一個
runtime.MessageSender物件,表示訊息的傳送者。 sendResponse-
一個函式,最多呼叫一次,用於將響應傳送回
message。該函式接受一個引數:任何可序列化的物件(請參閱 資料克隆演算法)。此引數將傳回給訊息傳送者。如果您在同一文件中有多個
onMessage()監聽器,那麼只有一個可以傳送響應。要同步傳送響應,請在監聽器函式返回之前呼叫
sendResponse()。要非同步傳送響應,請使用以下選項之一:
-
從監聽器函式返回一個
Promise,並在響應準備好時解析該 Promise。這是推薦的方法。 -
保留
sendResponse()引數的引用,並從監聽器函式中返回true。然後在監聽器函式返回後呼叫sendResponse()。注意: 在 Chrome 中,Promise 作為返回值不受支援,直到 Chrome bug 1185241 解決。作為替代方案,返回 true 並使用 sendResponse。
-
listener函式可以返回布林值或Promise。注意: 如果您將一個 async 函式傳遞給
addListener(),監聽器將為它收到的每條訊息返回一個 Promise,從而阻止其他監聽器響應。js// don't do this browser.runtime.onMessage.addListener(async (data, sender) => { if (data.type === "handle_me") { return "done"; } });假設您只想讓監聽器響應特定型別的訊息。在這種情況下,您必須將監聽器定義為非 async 函式,並且僅為監聽器旨在響應的訊息返回 Promise — 否則返回 false 或 undefined。
jsbrowser.runtime.onMessage.addListener((data, sender) => { if (data.type === "handle_me") { return Promise.resolve("done"); } return false; });
示例
簡單示例
此內容指令碼監聽網頁上的點選事件。如果點擊發生在連結上,它會向背景頁面傳送一條訊息,內容為目標 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 中,Promise 作為返回值不受支援,直到 Chrome bug 1185241 解決。作為替代方案,返回 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。