はじめに
ループしながらDOM(プログレスバーなど)を更新したい際、setTimeout
を使うと思います。
しかし、その際setTimeout
の 4ms がネックになることがあります。
アニメーションよりも速度が優先される場合、この 4ms は無駄です。
また、setTimeout
やrequestAnimationFrame
はページがノンアクティブになると、分解能が 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
最後に
ノンアクティブでも分解能が落ちません。