Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nulltask/31d3301b9b5c4fd78a97 to your computer and use it in GitHub Desktop.
Save nulltask/31d3301b9b5c4fd78a97 to your computer and use it in GitHub Desktop.
Web Worker をちょっと便利にするライブラリのご紹介

Web Worker をちょっと便利にするライブラリのご紹介

自己紹介

宣伝

__月刊ライトニングトーク__というウェブ系の勉強会を主催しています。

今のところだいたい隔月で開催中。場所は渋谷か上野でやることが多いです。

アンケート

Web Worker 使ってますか?

Web Worker おさらい

  • UI のイベントループとは独立したイベントループで処理を実行
    • OS のスレッドを使って実行
    • CPU bound な処理でも UI をブロックしない
  • 独立したスコープで処理を実行
    • UI 側のグローバルオブジェクトにアクセスできない
    • Worker 側でグローバル汚染しても UI 側に影響されない
  • DOM にアクセスすることができない
  • 代表的なユースケース
    • 巨大な JSON ファイルのシリアライズ
    • Canvas の ImageData のピクセル操作
    • ゲームなど FPS が重要なコンテンツの開発

Web Worker のインタフェース

  • main.js: メインスレッドから Worker を生成
var worker = new Worker('worker.js');

// worker からのメッセージを受信
worker.onmessage = function(e) {
  console.log(e.data);  // 1: HELLO
                        // 2: HELLO
                        // 3: HELLO ...
};

setInterval(function() {
  // worker へメッセージを送信
  worker.postMessage('hello');
}, 1000);
  • worker.js: 受け取ったデータを大文字に変換して返却
var count = 0;
// 生成元からのメッセージを受信するためのイベントリスナ
self.onmessage = function(e) {
  count++;
  // 生成元へメッセージを送信
  self.postMessage(count + ': ' + e.data.toUpperCase());
};

図にまとめると...

インタフェースについて個人的な不満

Worker 側のコードを別ファイルにしなければならない。

  • 気軽に Web Developer Console で試せない
  • タスクランナーで concat + minify したときの恩恵が受けられない
  • Browserify で worker 側のコードを require したい

こんな風にインラインでかければいいのに。

var worker = new Worker(function() {
  var count = 0;
  self.onmessage = function(e) {
    count++;
    self.postMesage(count + ': ' + e.data.toUpperCase());
  };
});

worker.onmessage = function(e) {
  console.log(e.data);
};

setInterval(function() {
  worker.postMessage('hello');
}, 1000);

できるようにしました

pseudo-function というライブラリをつくりました。

さっきのサンプルがインラインっぽく書けるようになります。

var fn = new PseudoFunction(function() {
  var count = 0;
  self.onmessage = function(e) {
    count++;
    self.postMessage(count + ': ' + e.data.toUpperCase());
  };
});

var worker = new Worker(fn);

worker.onmessage = function(e) {
  console.log(e.data);
};

setInterval(function() {
  worker.postMessage('hello');
}, 1000);

実現方法

  • 関数オブジェクトから URL.createObjectURL で Blob URL を生成
  • Blob URL は Blob オブジェクトを外部ファイルのように扱える
  • 上記の特徴を利用して Worker のコンストラクタに Blob URL を渡すことでインラインで記述可能

特徴

  • IE 11+, Firefox 12+, Chrome 26+, Safari 6+, Android 4.4+ に対応
  • Bower に対応 ($ bower install pseudo-function)
  • Browserify に対応 ($ npm install pseudo-function)
  • Component, Duo にも対応 (require('nulltask/pseudo-function'))
  • ユニットテスト付属、Travis CI でテストを実行
  • MIT ライセンス (商用利用に制限なし)

おまけ

pseudo-function を使って作った stable-timer というライブラリ。

どんな状況でも安定して動作するタイマー。 Worker 内の setTimeout, setInterval は生成元のタブやブラウザそのものがバックグランドに回っても分解能が変わらない特性を利用。

Worker 用のコードをインラインで記述しているため、ライブラリのユーザが意識しなくとも Web Worker による処理を利用できるようになった。

まとめ

ご静聴ありがとうございました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment