LoginSignup
27
29

More than 5 years have passed since last update.

別タブを選択しても精度の落ちないタイマー

Last updated at Posted at 2012-12-26

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

27
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
29