コンテンツスクリプトと拡張機能の間でメッセージをやり取りしようとしています
ここに私がコンテンツスクリプトに持っているものがあります
chrome.runtime.sendMessage({type: "getUrls"}, function(response) {
console.log(response)
});
バックグラウンドスクリプトには
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.type == "getUrls"){
getUrls(request, sender, sendResponse)
}
});
function getUrls(request, sender, sendResponse){
var resp = sendResponse;
$.ajax({
url: "http://localhost:3000/urls",
method: 'GET',
success: function(d){
resp({urls: d})
}
});
}
getUrls
関数でajax呼び出しの前に応答を送信すると、応答は正常に送信されますが、応答を送信するときのajax呼び出しの成功メソッドでは、応答を送信しません。デバッグsendResponse
関数のコード内でポートがヌルであることがわかります。
chrome.runtime.onMessage.addListener
のドキュメント から:
非同期で応答を送信することを示すためにイベントリスナーからtrueを返さない限り、イベントリスナーが戻ると、この関数は無効になります(これにより、sendResponseが呼び出されるまでメッセージチャネルが相手側に開かれたままになります)。
したがって、getUrls
への呼び出しの後にreturn true;
を追加して、応答関数を非同期に呼び出すことを示す必要があります。
受け入れられた答えは正しいです。これを単純化するサンプルコードを追加したかっただけです。問題は、特定のメッセージが非同期で処理されるかどうかを開発者に知らせるため、API(私の見解では)が適切に設計されていないことです。さまざまなメッセージを処理する場合、これは不可能なタスクになります。これは、渡されたsendResponseの一部の関数が非同期と呼ばれるかどうかがわからないためです。このことを考慮:
chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {
if (request.method == "method1") {
handleMethod1(sendResponse);
}
handleMethod1
呼び出しが非同期であるかどうかを知るにはどうすればよいですか? handleMethod1
を変更する人は、非同期のものを導入することで発信者を中断することをどのようにして知ることができますか?
私の解決策はこれです:
chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {
var responseStatus = { bCalled: false };
function sendResponse(obj) { //dummy wrapper to deal with exceptions and detect async
try {
sendResponseParam(obj);
} catch (e) {
//error handling
}
responseStatus.bCalled= true;
}
if (request.method == "method1") {
handleMethod1(sendResponse);
}
else if (request.method == "method2") {
handleMethod2(sendResponse);
}
...
if (!responseStatus.bCalled) { //if its set, the call wasn't async, else it is.
return true;
}
});
これは、メッセージの処理方法に関係なく、戻り値を自動的に処理します。これは、応答関数の呼び出しを忘れないことを前提としていることに注意してください。また、クロムは私たちのためにこれを自動化できたかもしれないことに注意してください、彼らがそうしなかった理由はわかりません。
私のライブラリ https://github.com/lawlietmester/webextension を使用して、コールバックなしでFirefoxの方法でChromeとFFの両方でこの作業を行うことができます。
コードは次のようになります。
Browser.runtime.onMessage.addListener( request => new Promise( resolve => {
if( !request || typeof request !== 'object' || request.type !== "getUrls" ) return;
$.ajax({
'url': "http://localhost:3000/urls",
'method': 'GET'
}).then( urls => { resolve({ urls }); });
}) );