chrome.runtime.onMessage.addListenerからのresponseがundefined
2022/03/27
chrome extensionの開発で、background.jsからのchrome.runtimeによるresponseがundefinedになる問題に少しつまづいたのでメモとして残しておきます。
undefinedが返ってくるcode
実際にundefinedが返ってくるbackground.js
codeのchrome.runtime部分は以下のとおりです。
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
const res = await somePromiseFunction();
sendResponse(res);
});
chrome.runtime.sendMessage('test', (res) => {
console.log(res) // undefined
});
return trueを追記してみる
MDNドキュメントによると...
either keep a reference to the sendResponse() argument and return true from the listener function. You will then be able to call sendResponse() after the listener function has returned.
listener function内でreturn true
をしないと、非同期的な処理では先にportが閉じてしまう(sendResponseが使えなくなる)ようです。
ということでbackground.js
にreturn true
を追記してみます。
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
const res = await somePromiseFunction();
sendResponse(res);
return true; // <- ここに追記
});
このtrueは非同期でメッセージ送るからsendResponse
が呼ばれるまではport空けといてほしいことをchrome runtimeに伝えるためのtrueです。
これでundefined問題は解決...
と言いたいところですが、これだけだとまだsendResponse
は機能しません。
async, awaitをやめる
勘が良い人は気づいているかもしれませんが、listener functionをasyncにしておくと、addListenerにはtrueがreturnされません。
つまり、async関数は実行時にtrue
ではなくPromise<boolean>
をすぐに返すので、結局portが閉じ、sendResponseが使えなくなるというわけです。
したがって、最終的に正しいcodeは以下の通りになります。
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
somePromiseFunction().then((res) => {
sendResponse(res);
});
return true;
});
somePromiseFunction
の処理中にtrue
を返せてるので、後からでも問題なくsendResponse
を使用できます。
おわり
browserによってはPromiseをreturnするだけでよさそう(chromeは現時点ではまだ対応してない)