latest log

酩酊状態で書いたエンジニアポエムです。酩酊状態で読んでください。

みんな大好き WebWorkers (WorkerMessage.js 作った)

WebWorkers(以下Worker)をハンドリングするのは結構大変で、ちゃんと意味があるコードを書こうとすると、

  • Worker が応答無くなったらどうしよう。エラーハンドリングどうしよう。どんなエラーがあるんだろう
  • Worker に job 投げて結果を受け取ってクローズしてという基本的な部分をもっと楽に書きたい
  • インラインワーカーどうしよう。インラインワーカーの場合の importScripts のパスの指定どうしよう
  • postMessageの呼び出しコストは大丈夫か? 十分な時間分解能があるんだろうか

などなど色々と考慮する必要があったりします。

このへんの事を考慮した実装がこちら( WebWorker.js )。半年ほど前の実装です。

で、かなり使いづらい(自分でも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で動きます。