BlobBuilder で 外部ファイルの要らない WebWorkers はつくれる
WebWorkersで別タブ選択中もきっちり動く無敵タイマーをつくる - つまみ食う
http://d.hatena.ne.jp/mohayonao/20111108/1320756534
先日書いたこのエントリーで、別タブを選択したときも精度が落ちないタイマーを作った。
でも、外部ファイルが必要だったのでライブラリ的なものに組み込むときにパスを自己解決できないという問題があった。
// 問題点:muteki-timer.js の設置場所が制限される // もしくはライブラリの外から muteki-timer.js の場所を教えてあげる必要がある var url = "muteki-timer.js"; var timer = new Worker(url);
今回は外部ファイルを使わない無敵タイマー。以下手順
- BlobBuilderっていうのを使ってコードを組み立てる。
- すごいと評判*1 の createObjectURL でURLを取得
- new Worker(url) する
ちなみに前回の方法は
MutekiTimerクラス
上記の方法で無敵タイマークラスを作った。
無敵タイマーが使えないときは通常の setInterval を使う。コードはエントリの最後。
デモ
無敵タイマー と 通常の setInterval の比較ページ。
別タブを選択して、しばらく放置して戻ってくると差が分かる。
http://mohayonao.herokuapp.com/mutekitimer
サンプル
無限インベンション
http://mohayonao.herokuapp.com/invention
6文字リズムマシン
http://mohayonao.hatenablog.com/entry/2011/11/21/202019
どちらも音のなるウェブ楽器で、別タブを選択中も音が鳴り続ける。
(以前は別タブを選択すると音が激しく途切れていた)
メモ
コード
function MutekiTimer() { this.initialize.apply(this, arguments); } MutekiTimer.prototype = { initialize: function() { var url = (function() { var BlobBuilder = window.WebKitBlobBuilder || window.MozBlobBuilder; var URL = window.URL || window.webkitURL; var MutekiTimerBlob; if (!BlobBuilder || !URL) return null; MutekiTimerBlob = new BlobBuilder(); MutekiTimerBlob.append("var timerId = 0;"); MutekiTimerBlob.append("this.onmessage = function(e) {"); MutekiTimerBlob.append(" if (timerId !== 0) {"); MutekiTimerBlob.append(" clearInterval(timerId);"); MutekiTimerBlob.append(" timerId = 0;"); MutekiTimerBlob.append(" }"); MutekiTimerBlob.append(" if (e.data > 0) {"); MutekiTimerBlob.append(" timerId = setInterval(function() {"); MutekiTimerBlob.append(" postMessage(null);"); MutekiTimerBlob.append(" }, e.data);"); MutekiTimerBlob.append(" }"); MutekiTimerBlob.append("};"); return URL.createObjectURL(MutekiTimerBlob.getBlob()); }()); if (url) { this._timer = new Worker(url); this.isMuteki = true; } else { this._timer = null; this.isMuteki = false; } this._timerId = 0; }, setInterval: function(func, interval) { if (this._timer) { this._timer.onmessage = function(e) { func(); }; this._timer.postMessage(interval); } else { if (this._timerId !== 0) { clearInterval(this._timerId); } this._timerId = setInterval(function() { func(); }, interval); } }, clearInterval: function() { if (this._timer) { this._timer.postMessage(0); } else { if (this._timerId !== 0) { clearInterval(this._timerId); } this._timerId = 0; } } };