在 Manifest V3 中,chrome.runtime.onMessage 的監聽器
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { // 注意:這裡移除了 async 關鍵字,因為 return true 必須是同步返回的
try {
if (request.from == "popup") {
// 異步操作開始
refreshAlarmList(true)
.then(() => {
console.log("refresh alarm list ok");
sendResponse({ message: "ok" });
})
.catch(error => {
console.error("refreshAlarmList: 出錯: ", error);
// 即使出錯,也應該調用 sendResponse,或者讓 popup 端處理超時
sendResponse({ message: "error", error: error.message });
});
// *** 關鍵:告訴 Chrome 這是一個異步響應 ***
return true;
} else {
// 對於同步響應,不需要 return true
sendResponse({ message: "no" });
return false; // 或者不 return 任何東西,但 return true 只在異步時需要
}
} catch (error) { // 這個 catch 捕獲的是 addListener 內部同步部分的錯誤,異步錯誤在 .catch 中處理
console.error("onMessage listener synchronous error: ", error);
// 也可以考慮在這裡 sendResponse 一個錯誤訊息
return false; // 如果在這裡捕獲了同步錯誤,也要表明不是異步的
}
});
// 假設 refreshAlarmList 是一個 async 函數
// async function refreshAlarmList(forceRefresh) { /* ... 您的邏輯 ... */ }
addListener 的回呼函數不再是 async: 為了能夠同步地 return true;,我們將 async 關鍵字從 addListener 的回呼函數上移除。使用 .then() 和 .catch() 處理 Promise: 由於 refreshAlarmList 是一個 async 函數(返回 Promise),我們使用 .then() 來處理成功的情況(並在其中調用 sendResponse),使用 .catch() 來處理失敗的情況(同樣在其中調用 sendResponse)。return true;: 這是最重要 的一步。在 if(request.from == "popup") 條件塊的末尾(在異步操作啟動之後),我們 return true;。這告訴 Chrome 保持通訊管道開啟,等待 sendResponse 被異步調用。同步路徑的處理: 對於不需要異步操作的 else 分支,我們可以直接調用 sendResponse,並且可以 return false; 或不返回任何東西(因為預設返回 undefined,不是 true,所以管道會關閉)。
// background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.from == "popup") {
// 假設 refreshAlarmList 是一個 async 函數
refreshAlarmList(true) // refreshAlarmList 內部可以使用 await getAlarmList() 等
.then(() => {
console.log("refresh alarm list ok");
sendResponse({ message: "ok" });
})
.catch(error => {
console.error("refreshAlarmList: 出錯: ", error);
sendResponse({ message: "error", error: error.message });
});
return true; // 關鍵!
} else {
sendResponse({ message: "no" });
// return false; // 或者不返回
}
// 注意:try...catch 最好放在 .then/.catch 內部或 refreshAlarmList 內部去處理異步錯誤
});
async function refreshAlarmList(forceRefresh) {
try {
console.log("Refreshing alarm list...");
// 您可以在這裡面安全地使用 await getAlarmList()
const list = await getAlarmList(); // 假設 getAlarmList 也是 async
// ... 執行您的刷新邏輯 ...
console.log("Alarm list refreshed successfully.");
} catch (error) {
console.error("Error in refreshAlarmList:", error);
throw error; // 可以向上拋出,讓 .catch 捕獲
}
}
async function getAlarmList(){ // 您的 async getAlarmList 函數
try {
const obj = await chrome.storage.local.get(['alarmlist']);
return obj.alarmlist || {};
} catch (error) {
console.error("讀取 alarmlist 時出錯:", error);
return {};
}
}
留言
張貼留言