1 つ目は、DOM の複数の読み取り操作 (または複数の書き込み操作) をまとめる必要があります。 2 つの読み取り操作の間に書き込み操作を追加しないでください。
第二に、再配置によって特定のスタイルが得られた場合、その結果をキャッシュするのが最善です。これにより、次回ブラウザを使用するときにブラウザをリフローする必要がなくなります。
3つ目は、スタイルを一つ一つ変更するのではなく、classやcsstext属性を変更することで一気にスタイルを変更します。
// badvar left = 10;var top = 10;el.style.left = left + "px";el.style.top = top + "px";// good el.className += " theclassname";// goodel.style.cssText += "; left: " + left + "px; top: " + top + "px;";
記事 4: 要素のスタイルを変更するには、リアル メッシュ DOM の代わりにオフライン DOM を使用してみてください。たとえば、Document Fragment オブジェクトを操作し、完了後にオブジェクトを DOM に追加します。別の例として、 cloneNode () メソッドを使用してクローン ノードを操作し、元のノードをクローン ノードに置き換えます。
項目 5: まず、要素を表示するように設定します: none (1 回の再配置と再描画が必要)、次にこのノードで 100 回の操作を実行し、最後に表示を復元します (1 回の再配置と再描画が必要)。この方法では、最大 100 回の再レンダリングの代わりに 2 回の再レンダリングが使用されます。
第6条:位置属性が絶対的または固定的である要素については、他の要素への影響を考慮する必要がないため、再配置のコストは比較的小さくなる。
第7条:不可視の要素は再配置や再描画に影響を与えないため、要素の表示属性は必要な場合にのみ可視に設定してください。さらに、visibility : hidden を持つ要素はリフローにのみ影響し、再描画には影響しません。
第8条、React等の仮想DOMスクリプトライブラリを使用する。
第9条、window.requestAnimationFrame()とwindow.requestIdleCallback()の2つのメソッドを使用して再レンダリングを調整します。
1. window.requestAnimationFrame ()
再レンダリングを調整し、Web ページのパフォーマンスを大幅に向上させることができる JavaScript メソッドがいくつかあります。
最も重要なのは window.requestAnimationFrame() メソッドです。次回の再レンダリング時に実行されるコードを配置できます。
function doubleHeight (element) { var currentHeight = element.clientHeight; element.style.height = (currentHeight * 2) + 'px';}elements.forEach (doubleHeight);
上記のコードは、ループ演算を使用して各要素の高さを 2 倍にしています。ただし、ループを通過するたびに、読み取り操作の後に書き込み操作が続きます。これにより、短期間に大量の再レンダリングがトリガーされ、明らかに Web ページのパフォーマンスに非常に悪影響を及ぼします。
window.requestAnimationFrame() を使用して読み取り操作と書き込み操作を分離し、すべての書き込み操作を次の再レンダリングに入れることができます。
function doubleHeight (element) { var currentHeight = element.clientHeight; window.requestAnimationFrame (function () { element.style.height = (currentHeight * 2) + 'px'; });}elements.forEach (doubleHeight);
ページ スクロール イベント (scroll) のリッスン関数は、次の再レンダリングまで延期する window.requestAnimationFrame() を使用するのに非常に適しています。
$(window) .on ('scroll', function() { window.requestAnimationFrame (scrollHandler);});
もちろん、最適な機会はWebアニメーションです。以下は、要素がフレームごとに 1 度回転する回転アニメーションの例です。
var rAF = window.requestAnimationFrame;var degrees = 0;function update () { div.style.transform = "rotate (" + degrees + "deg)"; console.log ('updated to degrees ' + degrees); degrees = degrees + 1; rAF (update);}rAF (update);
二、window.requestIdleCallback()
window.requestIdleCallback()という関数もあり、これも再レンダリングの調整に使用できます。
フレームの最後に空き時間がある場合にのみコールバック関数を実行することを指定します。
requestIdleCallback (fn);
上記のコードでは、関数 fn は現在のフレームの実行時間が 16.66ms 未満の場合にのみ実行されます。それ以外の場合は、次のフレームに延期され、次のフレームにアイドル時間がなければ、次のフレームに延期されます。
指定されたミリ秒数を示す 2 番目のパラメータも受け入れることができます。指定された期間内の各フレームにアイドル時間が存在しない場合、関数 fn が強制的に実行されます。
requestIdleCallback (fn, 5000);
上記のコードは、関数 fn が遅くとも 5000 ミリ秒後に実行されることを示しています。
関数 fn はパラメータとして期限オブジェクトを受け取ることができます。
requestIdleCallback (function someHeavyComputation (deadline) { while(deadline.timeRemaining () > 0) { doWorkIfNeeded (); } if(thereIsMoreWorkToDo) { requestIdleCallback (someHeavyComputation); }});
上記のコードでは、コールバック関数 someHeavyComputation のパラメータは期限オブジェクトです。
deadline オブジェクトには、timeRemaining() と DidTimeout という 1 つのメソッドと 1 つのプロパティがあります。
(1) timeRemaining()メソッド
timeRemaining()メソッドは、現在のフレームの残りミリ秒を返します。このメソッドは読み取りのみ可能で書き込みはできず、動的に更新されます。したがって、このプロパティを常に確認し、まだ時間が残っている場合は、特定のタスクの実行を続けることができます。この属性が 0 に等しくなると、タスクは requestIdleCallback の次のラウンドに割り当てられます。
前のコード例では、現在のフレームに空き時間がある限り、doWorkIfNeeded メソッドが呼び出され続けます。アイドル時間がなくなってもタスクが完全に実行されていない場合、そのタスクは requestIdleCallback の次のラウンドに割り当てられます。
(2) DidTimeout 属性
期限オブジェクトの DidTimeout 属性は、指定された時間が経過したかどうかを示すブール値を返します。これは、指定された時間が経過したためにコールバック関数が起動した場合、2 つの結果が得られることを意味します。
因此,如果回调函数执行了,无非是两种原因:当前帧有空闲时间,或者指定时间到了。
function myNonEssentialWork (deadline) { while ((deadline.timeRemaining () > 0 || deadline.didTimeout) && tasks.length > 0) doWorkIfNeeded (); if (tasks.length > 0) requestIdleCallback (myNonEssentialWork);}requestIdleCallback (myNonEssentialWork, 5000);
上面代码确保了,doWorkIfNeeded 函数一定会在将来某个比较空闲的时间(或者在指定时间过期后)得到反复执行。
requestIdleCallback 是一个很新的函数,刚刚引入标准,目前只有 Chrome 支持。