operativeでWebWorkersを手軽に扱う

WebWorkersをあまり活用できていなくて、活用したいなーと思っていろいろ調べていたらoperativeに行き着いたのでメモ。

そもそもなぜ活用できていないかというと、古いIEへの対応のために分岐が必要だったり、 ソースコードを別ファイルに分割しないといけなかったり、少し面倒だったため。 WebWorkersに直接関数を渡して、Promiseで書きたいし、古いブラウザのために分岐を書きたくない。 と、いろいろ調べていたらoperativeを見つけた。

operativeは上に書いた面倒なことや、やりたいことを全部解決してくれるもの。 直接関数を渡すとそれをWebWorkers上で動作するようにしてくれるし、 古いブラウザではWebWorkers以外の方法で動作するようにフォールバックしてくれるし、 Promiseが使用できればPromiseで書ける。

基本的な使い方は以下のようになる。

var operation = operative(
  // この関数はWebWorkersで動作する
  function(a, b, callback) {
    setTimeout(function() {
      callback(a + b);
    }, 0);
  }
);

operation(1, 2, function(result) {
  console.log(result);
});

WebWorkersで動作させたい関数を直接渡せる。(コンテキストが異なるというのがぱっと見ではわからないので、そこはあまりよろしくないかもしれないけど) たぶん、関数を文字列化してURLにして渡してるのかな。

Promiseを使いたい場合は以下のようになる。

var operation;

if (!window.Promise) {
  operative.Promise = ES6Promise.Promise;
}

operation = operative(function(value) {
  var deferred = this.deferred();

  setTimeout(function() {
    if (value) {
      deferred.reject('reject');
    } else {
      deferred.fulfill('fulfill');
    }
  }, 0);

  return deferred;
});

operation(true)
  .then(function(text) {
    console.log(text);
  })
  ['catch'](function(err) {
    console.error(err);
  });

operativeはwindow.Promiseがあればそれを使ってくれるのだけど、存在しない場合にoperative.Promiseを指定する必要がある。 ここではES6Promiseを使ってるという仮定でES6Promise.Promiseを代入してる。こんなことをせずにES6Promise.polyfill()を先に呼んでおいても良いのだけど。

operativeに渡す関数ではPromiseでなくthis.deferred()でdeferredを取得して、それを使用する必要がある。 メソッド名が若干Promiseと異なるけれど、成功したときはfulfillを失敗したときはrejectを呼べばいい。

というわけで何も考えずにさっと書きたいときはoperativeを使えば良いかなと思った。


その他、調べているときに見つけたモジュールなど。