JavaScriptで定期的な処理を行う場合、window.setIntervalを使いますが、ChromeやFirefoxのwindow.setIntervalは別タブを選択すると精度(実行間隔)が落ち、例えばゲームや音声処理などで精度を保ちたい場合に問題になることがあります。
WebWorkersを使ってバックグラウンドでタイマーを動作させると、別タブを選択しても精度の落ちないタイマーを作ることができます。
mutekitimer.js
var MutekiTimer = (function() {
var MutekiTimer = function() {
initialize.apply(this, arguments);
}, $this = MutekiTimer.prototype;
var TIMER_PATH = (function() {
var BlobBuilder, URL, builder;
BlobBuilder = self.WebKitBlobBuilder || self.MozBlobBuilder;
URL = self.URL || self.webkitURL;
if (BlobBuilder && URL) {
builder = new BlobBuilder();
builder.append("var timerId = 0;");
builder.append("this.onmessage = function(e) {");
builder.append(" if (timerId !== 0) {");
builder.append(" clearInterval(timerId);");
builder.append(" timerId = 0;");
builder.append(" }");
builder.append(" if (e.data > 0) {");
builder.append(" timerId = setInterval(function() {");
builder.append(" postMessage(null);");
builder.append(" }, e.data);");
builder.append(" }");
builder.append("};");
return URL.createObjectURL(builder.getBlob());
}
return null;
}());
var initialize = function() {
if (TIMER_PATH) {
this._timer = new Worker(TIMER_PATH);
this.isMuteki = true;
} else {
this._timer = null;
this.isMuteki = false;
}
this._timerId = 0;
};
$this.setInterval = function(func, interval) {
if (this._timer !== null) {
this._timer.onmessage = func;
this._timer.postMessage(interval);
} else {
if (this._timerId !== 0) {
clearInterval(this._timerId);
}
this._timerId = setInterval(func, interval);
}
};
$this.clearInterval = function() {
if (this._timer !== null) {
this._timer.postMessage(0);
} else if (this._timerId !== 0) {
clearInterval(this._timerId);
this._timerId = 0;
}
};
return MutekiTimer;
}());
usage.js
var div1 = document.createElement("div");
var div2 = document.createElement("div");
var counter1 = 0;
var counter2 = 0;
var timer = new MutekiTimer();
console.log("MutekiTimer is " + (timer.isMuteki ? "availabled" : "disabled") +".");
timer.setInterval(function() {
div1.innerHTML = counter1++;
}, 50); // 別タブを選択して戻ってきても精度が落ちない
window.setInterval(function() {
div2.innerHTML = counter2++;
}, 50); // 別タブを選択して戻ってくると精度が落ちている
document.body.appendChild(div1);
document.body.appendChild(div2);
2012/04/30追記
Mac版Firefox12.0にバグがあるっぽいので対策について書きました。
http://qiita.com/items/32fbf90bf545de8df768