Edited at

setTimeoutの限界を超える

More than 3 years have passed since last update.


はじめに

ループしながら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


最後に

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