當年(其實也就是幾個月以前)在製作 extension 某個功能的時候需要呼叫 chrome.tabs API 來拿一些資料再送回去給 content,於是就寫出了像下面這樣的 code:
/* file: content_script.js */
chrome.runtime.postMessage({action: 'tabs information'}, function(res) {
/**
* Do something with tabs information
*/
});/* file: background.js */
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action === 'tabs information') {
// Query all tabs for information
chrome.tabs.query({}, function (tabs) {
var info = [];
tabs.forEach(function (tab) {
info.push({
id: tab.id,
title: tab.title,
url: tab.url
});
});
// Send it back with `sendResponse` function
sendResponse(info);
});
}
});看起來沒什麼大問題,但很遺憾的,這樣並不 work 。
我當時百思不得其解,用 Chrome DevTools 不停的 debug,花了一個下午的時間直到我在 chrome.runtime.onMessage 的文件裡面看到…
This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until
sendResponseis called).
看來是預設的情況之下, event listener 跑完就會把 sendResponse 用的 message channel 關起來,因此如果你需要 sendResponse 是在 asynchronous 的情況下被呼叫的話(基本上大部分的 chrome.* API 都是 asynchronous callback 的形式),在 event listener 的最後需要 return true。
所以只要稍微修改一下 background.js 就行了!
/* file: background.js */
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action === 'tabs information') {
// Query all tabs for information
chrome.tabs.query({}, function (tabs) {
var info = [];
tabs.forEach(function (tab) {
info.push({
id: tab.id,
title: tab.title,
url: tab.url
});
});
// Send it back with `sendResponse` function
sendResponse(info);
});
// Keep the message channel open until the `sendResponse` is called
return true;
}
});一行,一下午。

