LoginSignup
26
27

More than 5 years have passed since last update.

setTimeoutの限界を超える

Last updated at Posted at 2015-04-24

はじめに

ループしながらDOM(プログレスバーなど)を更新したい際、setTimeoutを使うと思います。
しかし、その際setTimeoutの 4ms がネックになることがあります。
アニメーションよりも速度が優先される場合、この 4ms は無駄です。

また、setTimeoutrequestAnimationFrameはページがノンアクティブになると、分解能が 1000ms に落ちます。

参考

もう5年前の記事ですが、こんなものがありました。
postMessageを利用したものです。
setTimeout with a shorter delay

クロスブラウザ対応したものもありました。
Cross-browser-compatible setZeroTimeout

コード

少々改良しました。

setZeroTimeout.js
var setZeroTimeout = (function(global) {
    var timeouts = [];
    var messageName = "zero-timeout-message";

    function handleMessage(event) {
        if (event.source == global && event.data == messageName) {
            if (event.stopPropagation) {
                event.stopPropagation();
            }
            if (timeouts.length) {
                timeouts.shift()();
            }
        }
    }

    if (global.postMessage) {
        if (global.addEventListener) {
            global.addEventListener("message", handleMessage, true);
        } else if (global.attachEvent) {
            global.attachEvent("onmessage", handleMessage);
        }

        return function (fn) {
            timeouts.push(fn);
            global.postMessage(messageName, "*");
        }
    } else {
        return function () {
            setTimeout(fn, 0);
        }
    }
}(window));

使い方

ループしながらDOMを更新します。

example.js
function loop() {
    // DOMを更新するプログラム
    // ...
    setZeroTimeout(loop);
}
loop();

デモ

要素をクリックするとカウントが始まります。
setZeroTimeout - JSFiddle

最後に

ノンアクティブでも分解能が落ちません。

26
27
1

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
26
27