JSで非同期処理をする際に便利なインラインワーカーですが、ワーカーは通常ブラウザjsとは別のグローバルスコープで実行されるため、型付のHaxeでは使用するのがちょっと面倒でした。
インラインワーカーについてはこちらの記事を参考にしています。
WorkerUtil.hx
class WorkerUtil {
static var reg = new RegExp("^function\\s*\\w*\\s*\\([\\w\\s,]*\\)\\s*{([\\w\\W]*?)}$", "i");
public static function createInlineWorker(workerFunc: Dynamic): Worker {
var func = workerFunc.toString().trim().match(reg)[1];
var blob = new Blob([ func ], { type: "text/javascript" });
var url = URL.createObjectURL(blob);
return new Worker(url);
}
}
Main.hx
var worker = WorkerUtil.createInlineWorker(function() {
var global: DedicatedWorkerGlobalScope = js.Lib.eval("self");
global.onmessage = function(m: MessageEvent) {
global.postMessage(m.data+"!!");
};
});
worker.onmessage = function(m: MessageEvent) {
trace(m.data); // Hello World!!
}
worker.postMessage("Hello World");
当初、通常のjsのように、ワーカーで実行される無名関数内のスコープが実行時ワーカースコープになるという特徴をどうHaxeで実現するか悩んだのですが、結果的に、 JavaScriptのevalが常にグローバルスコープで評価される という特徴を思い出し、eval("self")をすればいいと気がつきました。WebWorkerのグローバルスコープには上記のMDNのようないくつかの関数と変数が登録されており、それらはWorkerGlobalScopeというインラーフェースとしていくつかの実装系があります。通常のWebWorkerの場合、DedicatedWorkerGlobalScopeというクラスになるため、selfの値はそのインスタンスになります。なので、このような形で書くことによってHaxeのコンパイラのエラーを回避できます。