##前書
普通にbackgroundに関数を追加して普通にContentScriptから呼びたい
##background側
- オブジェクトに関数をまとめる
- オブジェクト内の関数名を配列にして渡す
- オブジェクト内の関数を実行する
"use strict"
//エクスポートする関数
const ExportFuncs = {
TestFunc : (a, b, c) =>{
return a + b + c;
},
TestFuncAsync : (a, b, c) =>{
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(a * b * c);
}, 2000);
});
},
}
//イベントリスナー
chrome.runtime.onMessage.addListener(function( message, sender, sendResponse ) {
if( message.to === "background" ){
//new Promiseはreturn trueを先に返すための小細工
new Promise(async (resolve)=>{
if( message.msgType === "getFuncNames" ){
//ExportFuncs内の関数名を配列にしてレスポンスとして返す
sendResponse(
Object.keys(ExportFuncs).filter((key)=>{
//一応関数でフィルター
return typeof(ExportFuncs[key])==="function";
})
);
}else if( message.msgType === "execFunc" ){
//ExportFuncs内の関数を実行して結果をレスポンスとして返す
sendResponse(await ExportFuncs[message.funcName](...(message.args||[])))
}
resolve();
});
//タイムアウト防止
return true;
}
});
##Content Script側
- ExportFuncs内の関数名の配列から、実行させるためのメッセージを送る関数をまとめたオブジェクトを作成する
- ↑から関数を実行する
"use strict";
(async ()=>{
//初期化処理
const backgroundFuncs = await (new Promise((resolve)=>{
//関数名の配列を取得
chrome.runtime.sendMessage({
to:"background",
msgType:"getFuncNames",
},(response)=>{
//配列をオブジェクトにまとめる
resolve(response.reduce((funcs, key)=>{
//ExportFuncs内の関数を実行させるためのメッセージを送る関数
funcs[key] = (...args)=>{
//awaitできるように、Promiseでラップする
return new Promise((resolve)=>{
chrome.runtime.sendMessage({
to:"background",
msgType:"execFunc",
funcName: key,
args:args,
},(response)=>{
resolve(response);
});
});
};
return funcs;
},{}));
});
}));
//呼ぶ処理
console.log(await backgroundFuncs.TestFunc(2, 3, 5)); // 10
console.log(await backgroundFuncs.TestFuncAsync(2, 3, 5)); // 30
})();
##課題
- Content Script側をもっとコンパクトにしたいが、background側で関数作って文字列にして送ってevalで戻すくらいしか思いつかないし、そこまでやってもそんなにコンパクトにならない気がする
- chromeではtop-levelのawaitができた気がするがうまくいかない。何故だろう
##後書
- 関数自体の定義と実行に手を加えずにすんだのは満足