みんな大好き WebWorkers (WorkerMessage.js 作った)
WebWorkers(以下Worker)をハンドリングするのは結構大変で、ちゃんと意味があるコードを書こうとすると、
- Worker が応答無くなったらどうしよう。エラーハンドリングどうしよう。どんなエラーがあるんだろう
- Worker に job 投げて結果を受け取ってクローズしてという基本的な部分をもっと楽に書きたい
- インラインワーカーどうしよう。インラインワーカーの場合の importScripts のパスの指定どうしよう
- postMessageの呼び出しコストは大丈夫か? 十分な時間分解能があるんだろうか
などなど色々と考慮する必要があったりします。
このへんの事を考慮した実装がこちら( WebWorker.js )。半年ほど前の実装です。
- https://github.com/uupaa/WebWorker.js/blob/master/lib/WebWorker.js (409行)
- https://github.com/uupaa/WebWorker.js/blob/master/lib/WorkerThread.js (125行)
で、かなり使いづらい(自分でもAPI覚えきれないな)と思い、 MessageChannel を2本使い、メッセージとコントロールメッセージを分離した形で書きなおしたのがこちら( WorkerMessage.js )、
500行が180行になったよスッキリ。
あ、インラインワーカーの時のimportScriptsの指定とか、オリジンを指定する機能などは、わりとニッチな機能で、あまり重要じゃなかったことに気がついたので省略しました(ぺろり
MessageChannel で書きなおしたはいいんですが、Blinkの実装にバグがあり、
MessageChannel.portN.postMessage の第二引数が壊れている(event.data が nullになる)のが玉に瑕です。
困りましたね。
WorkerMessage.js のドキュメントはこれから書きますが、
APIそのものは非常にシンプルで、new WorkerMessage(...) して worker.post() して worker.close() する。生きてるかどうかは worker.isAlive() で確認みたいな感じです。たったの3〜4個です。
var worker = new WorkerMessage("worker.js", function(event) { // WorkerThread で worker.post() するとここに入る console.log(event.data); // "HELLO WORLD" worker.close(); }, function(exitCode, errorMessage) { // WorkerThread で ready() や cancel() するとここにくる。タイムアウトやエラーでもくる switch (exitCode) { case WorkerMessage.EXIT_CODE.OK: // 0 console.log("Safely closed."); break; case WorkerMessage.EXIT_CODE.ERROR: // 1 console.log("Terminates with an error from WorkerThread. " + errorMessage); break; case WorkerMessage.EXIT_CODE.FORCE: // 2 console.log("Forced termination by user."); break; case WorkerMessage.EXIT_CODE.TIMEOUT: // 3 console.log("Watchdog barked."); break; } }); worker.post("HELLO");
// worker.js importScripts("lib/WorkerMessage.js"); var worker = new WorkerMessage("", function(event) { // MainThread で worker.post() するとここに入る worker.post(event.data + " WORLD"); }, function(ready, cancel) { // MainThread で worker.close() するとここが呼ばれる。ready() または cancel() で応答する // .... destruction process... ready(); // -> WORKER_CLOSE_READY //cancel(); // -> WORKER_CLOSE_CANCEL });
WebModule なので、同じjsソースコードがブラウザとWebWorkerで動きます。