訊息傳遞
Background Service Worker、Content Script、Popup/Options 頁面各自執行在獨立、互相隔離的環境中,無法直接呼叫彼此的函式或共用變數。訊息傳遞(message passing)是它們之間唯一的溝通方式,理解它就能把 核心架構 提到的各個元件真正串起來。
一次性訊息:sendMessage / onMessage
最常用的模式,適合「問一句、答一句」的情境。
Content Script 或 Popup:發送訊息
chrome.runtime.sendMessage({ type: "GET_NOTES" }, (response) => {
console.log("收到的筆記:", response);
});
Background:接收並回應
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === "GET_NOTES") {
chrome.storage.local.get("notes", (result) => {
sendResponse(result.notes ?? []);
});
return true; // 必須回傳 true,Chrome 才會等待非同步的 sendResponse
}
});
return true 是最容易忽略的細節:onMessage 的監聽器預設是同步的,一執行完就會關閉溝通通道;如果 sendResponse 是在 chrome.storage.local.get 的回呼裡才呼叫(非同步),沒有回傳 true,回應就會遺失。
對特定分頁送訊息:tabs.sendMessage
chrome.runtime.sendMessage 送出的訊息只有 Background 與其他擴充功能頁面收得到,收不到 Content Script 的訊息。要主動通知某個分頁的 Content Script,要用 chrome.tabs.sendMessage 並指定 tabId:
Background:通知目前分頁的 Content Script
chrome.action.onClicked.addListener(async (tab) => {
const response = await chrome.tabs.sendMessage(tab.id, { type: "HIGHLIGHT" });
console.log(response);
});
反過來,Content Script 要送訊息給 Background,一律用 chrome.runtime.sendMessage(不能用 tabs.sendMessage,因為 Background 沒有 tabId)。
長連線:runtime.connect
如果需要持續、多次來回傳遞訊息(例如即時同步輸入內容),一問一答的 sendMessage 每次都要重新建立通道,效率較差,這時適合用 chrome.runtime.connect 建立長連線(Port):
建立連線端
const port = chrome.runtime.connect({ name: "sync-channel" });
port.postMessage({ type: "PING" });
port.onMessage.addListener((msg) => console.log("收到:", msg));
接收連線端
chrome.runtime.onConnect.addListener((port) => {
port.onMessage.addListener((msg) => {
port.postMessage({ type: "PONG", received: msg });
});
});
該用哪一種?
| 情境 | 建議 |
|---|---|
| 單次請求、單次回應 | sendMessage / onMessage |
| 通知特定分頁的 Content Script | tabs.sendMessage |
| 需要持續、高頻率的雙向溝通 | runtime.connect(長連線 Port) |
下一步
掌握訊息傳遞後,核心架構 四大元件就完整串起來了。接著前往 常用 API,深入認識 chrome.storage、chrome.tabs 等最常用的 API。