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を使えば良いかなと思った。
その他、調べているときに見つけたモジュールなど。
- https://github.com/mohayonao/inline-worker
- 古いブラウザへの対応が必要ない場合に良いかもしれない
- https://github.com/webpack/worker-loader
- webpackを使っているときにどうぞ
- https://github.com/webpack/webpack/tree/master/examples/web-worker
- worker-loaderを使ったWebWorkersを使うサンプル