JavaScriptのsetTimeout()は、高負荷の下で遅くなります
-
05-07-2019 - |
質問
要素の背景色をフェードさせるスクリプトを作成しました。 setTimeout()を使用して、5ミリ秒ごとに色を徐々に変更します。一度に1つのものの背景色をフェードしているだけでスクリプトはうまく機能しますが、たとえば50個の要素を一度にすべてフェードしている場合、すべての理由で速度が5ミリ秒よりもはるかに遅くなります同時に実行される同時setTimeout()s。たとえば、通常1秒で実行されるフェードは、一度に50個の要素をフェードしている場合、30秒かかることがあります。
これを克服する方法はありますか?
誰かがアイデアを持っている場合のスクリプトは次のとおりです。
function fadeBackground(elementId, start, end, time) {
var iterations = Math.round(time / 5);
var step = new Array(3);
step[0] = (end[0] - start[0]) / iterations;
step[1] = (end[1] - start[1]) / iterations;
step[2] = (end[2] - start[2]) / iterations;
stepFade(elementId, start, step, end, iterations);
}
function stepFade(elementId, cur, step, end, iterationsLeft) {
iterationsLeft--;
document.getElementById(elementId).style.backgroundColor
= "rgb(" + cur[0] + "," + cur[1] + "," + cur[2] + ")";
cur[0] = Math.round(end[0] - step[0] * iterationsLeft);
cur[1] = Math.round(end[1] - step[1] * iterationsLeft);
cur[2] = Math.round(end[2] - step[2] * iterationsLeft);
if (iterationsLeft > 1) {
setTimeout(function() {
stepFade(elementId, cur, step, end, iterationsLeft);
}, 5);
}
else {
document.getElementById(elementId).style.backgroundColor
= "rgb(" + end[0] + "," + end[1] + "," + end[2] + ")";
}
}
次のように使用されます:
fadeBackground("myList", [98,180,232], [255,255,255], 1000);
解決
記事著者がGmailのタイマーに関する作業について議論しているGoogleから。タイマーを頻繁に使用する場合、単一の高周波タイマーを使用する方が、複数のタイマーを使用するよりも高速であることがわかりました。
5msごとに起動するタイマーを1つ用意し、フェードする必要があるすべての要素を、フェード処理中の場所を追跡するデータ構造に追加することができます。次に、1つのタイマーがそのリストを調べて、各要素がトリガーされるたびに次のフェードを実行できます。
一方、 Mootools や JQuery 独自のアニメーションフレームワークを展開するのではなく?開発者は、この種の操作を最適化するために多くの作業を費やしました。
他のヒント
まず第一に、ブラウザによっては最小タイムアウトが通常10〜15ミリ秒であることをスクリプトが考慮していません。 このトピックに関する私の投稿。内部には、人気のあるブラウザーの表と、それを測定するプログラムへのリンクがありますので、自分で主張を確認できます。申し訳ありませんが、5msごとの反復は希望的観測です。
第二に、タイマーは割り込みではありません。それらには魔法はありません—ブラウザで実行されているものを中断してペイロードを実行することはできません。代わりに、実行中のコードが終了し、ブラウザがコントロールとタイマーを実行する機能を取り戻すまで、それらは延期されます。 50要素のフェードには時間がかかります。特に、ブラウザの遅延モデル全体を考慮すると、5ミリ秒を超えると思います。DOMを更新すると、ブラウザは視覚表現を更新します…ある時点で。
肯定的なコメントで終わりたい:
- 50個の個々の要素をフェードアウトする代わりに、それらをグループ化し、親をフェードアウトします—より高速になります。
- UIの創造性を高めます。一度に多くの独立した要素をフェードアウトする必要のない解決策を考えてみてください。
- 周囲を設計する前に、背景の仮定が正しいことを常に確認してください。
- 可能であれば、最新のブラウザをターゲットにしてみてください。私の個人的な経験から、Google Chromeはタイマーに非常に優れており、JavaScriptエンジン(V8)は非常に高速です。
他の回答に加えて、タイマーに関するJohn Resigの優れた記事を以下に示します。 http://ejohn.org/blog/how-javascript-timers-work/