我正在开发一个提取元数据的 Chrome 扩展。解析元数据的代码包含在内容脚本中。 background.js 和 content.js 通过 sendMessage 请求和响应进行通信。我遇到了 sendMessage 请求的异步性质的问题,并且我不确定如何解决它(即使在阅读了有关该问题的一连串讨论之后)。任何建议或指导将不胜感激。我怀疑我不知道如何将它们变成回调。
背景.js:
function onContextClick(info, tab) {
if( info["selectionText"] ){
var x = getMeta(tab);
//do stuff with x
}
}
function getMeta (tab) {
chrome.tabs.sendMessage(tab.id, {fetchTag: "meta,name,author,content"}, function(response) {
//alert(response.data);
//one thing I tired was to put my "do stuff" embedded here, but that didn't work either
return response.data;
});
}
var menu_id = chrome.contextMenus.create({"title": "Get Meta", "contexts":["selection"], "onclick": onContextClick});
内容.js:
function fetchTag(string) {
var param = string.split(",");
return $(param[0] + "["+param[1]+ "=\"" + param[2] + "\"]").attr(param[3]);
}
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.fetchTag.length > 0)
sendResponse({data: fetchTag(request.fetchTag)});
});
来自:https://developer.chrome.com/extensions/runtime#event-onMessage
当您有响应时调用的函数(最多一次)。参数应该是任何可 JSON 的对象。如果同一文档中有多个 onMessage 侦听器,则只有一个可以发送响应。当事件监听器返回时,此函数将变得无效,除非您从事件监听器返回true以指示您希望异步发送响应(这将使消息通道保持对另一端开放,直到调用sendResponse)。
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.fetchTag.length > 0)
sendResponse({data: fetchTag(request.fetchTag)});
return true;
});
然后它将与异步代码一起使用。
就我而言,
return true
没有帮助listener
中的 onMessage
设置为 async
并使用 await
等待异步响应并使用 sendResponse
发送它没有帮助没有帮助,我的意思是 Chrome 控制台中发生以下错误:
Unchecked runtime.lastError: The message port closed before a response was received.
经过一些实验,我发现以下方法可以很好地异步发送响应。
// content.js
chrome.runtime.sendMessage({ type: "GET_FOO" }, function (response) {
console.log(response.foo);
});
// background.js
// replace with a real call that
// needs to run asynchronously
async function getFoo() {
return "bar"
}
async function sendFoo(sendResponse) {
const foo = await getFoo()
sendResponse({ foo })
}
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.type === "GET_FOO") {
sendFoo(sendResponse)
return true
}
}
);
在 Chrome 92.0.4515.159(官方版本)(x86_64) 上测试。
我按照医生的要求进行了一切操作(或者我认为我做到了),包括返回
true
,但它不起作用。
花了几个小时咒骂自己后,我发现导致问题的是:
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
// ...
你注意到了吗?是的,
async
关键字使事件处理程序成为异步函数,并且它破坏了功能。
确保您的消息处理程序是一个同步函数。否则,
return true
没有帮助。
在内容脚本中。下面将返回未定义的弹出窗口或后台脚本。
(() => {
chrome.runtime.onMessage.addListener(
async (request, sender, sendResponse) => {
console.log("Message from the popup script:");
console.log(request);
setTimeout(() => {
sendResponse({ message: "Action is done" });
}, 5000);
return true;
// sendResponse({ message: "Action is done" });
}
);
})();
下面将返回预期的响应
(() => {
chrome.runtime.onMessage.addListener(
(request, sender, sendResponse) => {
console.log("Message from the popup script:");
console.log(request);
setTimeout(() => {
sendResponse({ message: "Action is done" });
}, 5000);
return true;
// sendResponse({ message: "Action is done" });
}
);
})();
您可以使用闭包。就这样。
function onContextClick(info, tab) {
if( info["selectionText"] ){
getMeta(tab, function(x){
console.log(x);
//do stuff with x
});
}
}
function getMeta (tab, callback) {
chrome.tabs.sendMessage(tab.id, {fetchTag: "meta,name,author,content"}, function(response) {
//alert(response.data);
//one thing I tired was to put my "do stuff" embedded here, but that didn't work either
callback(response.data);
});
}