ホームページ > ウェブフロントエンド > jsチュートリアル > ブラウザのレンダリングパフォーマンスの最適化

ブラウザのレンダリングパフォーマンスの最適化

巴扎黑
リリース: 2017-06-26 11:53:49
オリジナル
1910 人が閲覧しました

レンダリング パフォーマンス

ページは素早く読み込まれるだけでなく、スムーズに実行される必要があります。スクロールは指のスワイプと同じくらい速く、アニメーションとインタラクションはシルクのようにスムーズである必要があります。

60fps 対 デバイスのリフレッシュ レート

現在、ほとんどのデバイスの画面のリフレッシュ レートは、60 /です。したがって、ページにアニメーションまたはグラデーション効果がある場合、またはユーザーがページをスクロールしている場合、ブラウザーがアニメーションまたはページの各フレームをレンダリングするレートは、デバイス画面のリフレッシュ レートと一致している必要があります。

各フレームに割り当てられた時間は、16 ミリ秒強です (1 秒/60 = 16.66 ミリ秒)。しかし実際には、ブラウザにはいくつかの整理作業があるため、 10 ms以内にすべての作業を完了する必要があります。この予算を満たせない場合、フレームレートが低下し、コンテンツの画面にジャダーが表示されます。この現象は、ジャンク (ジャンク) と呼ばれることが多く、ユーザー エクスペリエンスに悪影響を及ぼします。

ピクセルパイプライン

作業する際に理解し、注意を払うべき主な領域が 5 つあります。これらは最も制御力があり、ピクセルから画面へのパイプラインの重要なポイントです:

  • JavaScript。一般に、JavaScript は視覚的な変更を実現するために使用されます。たとえば、jQuery の animate 関数を使用して、アニメーションを作成したり、データ セットを並べ替えたり、いくつかの DOM 要素をページに追加したりできます。 JavaScript 以外にも、CSS アニメーション、トランジション、Web アニメーション API など、視覚的な変更を実現する一般的な方法があります。

  • スタイル計算スタイル計算。これは、一致するセレクター (.headline や .nav > など) に基づいて、どの CSS ルールがどの要素に適用されるかを判断するプロセスであり、ルールがわかったら、それが適用され、各要素の最終的なスタイルが決定されます。

  • レイアウトが計算されます。要素に適用されるルールがわかったら、ブラウザはその要素が占めるスペースの量と画面上の位置の計算を開始できます。 Web ページのレイアウト モードは、1 つの要素が他の要素に影響を与える可能性があることを意味します。たとえば、

    要素の幅は、ツリー内のすべての子要素とノードの幅に影響します。という処理が頻繁に発生します。
  • 絵を描く。描画とはピクセルを埋めるプロセスです。これには、要素の目に見えるすべての部分を含む、テキスト、色、画像、境界線、影の描画が含まれます。描画は通常、複数のサーフェス (レイヤーと呼ばれることが多い) 上で行われます。

  • 合成。ページの一部は複数のレイヤーに描画される場合があるため、ページを正しくレンダリングするには、正しい順序で画面に描画する必要があります。これは、別の要素と重なる要素の場合に特に重要です。間違えると、ある要素が別の要素の上に誤って表示される可能性があるためです。

パイプラインのあらゆる部分で不具合が発生する可能性があるため、コードがパイプラインのどの部分をトリガーするかを正確に知ることが重要です。

すべてのフレームが常にパイプラインのすべての部分を通過するわけではありません。実際、JavaScript、CSS、Web アニメーションのいずれを使用する場合でも、指定したフレームに対してパイプラインを実行するには、次の 3 つの方法があります。

1. ; 合成

要素の「レイアウト」属性を変更する場合、つまり要素の幾何学的プロパティ (幅、高さなど) を変更する場合、ブラウザは他のすべての要素をチェックする必要があります。次に、ページを「自動的にリフロー」します (ページをリフローします)。影響を受けるパーツは再ペイントする必要があり、最終的にペイントされた要素を合成する必要があります。

2. JS/CSS > 描画 > 合成

「ペイントのみ」のプロパティ (背景画像、テキストの色、影など) を変更する場合ページ レイアウトに影響を与えない場合、ブラウザはレイアウトをスキップしますが、描画は引き続き実行されます。

3. JS / CSS > スタイル > 合成

再レイアウトも再描画も必要としないプロパティを変更した場合、ブラウザは合成のみを実行します。この最後のアプローチはオーバーヘッドが最も少なく、アニメーションやスクロールなど、アプリケーションのライフサイクルにおけるストレスの高いポイントに最適です。

パフォーマンスとは、実行を回避し、実行する操作を可能な限り効率的にする技術です。 多くの場合、これにはブラウザに対してではなく、ブラウザとの連携が必要です。 上記のさまざまなパイプライン ジョブは計算オーバーヘッドが異なり、一部のタスクは他のタスクよりも高価であることに留意する価値があります。

JavaScript の実行を最適化する

JavaScript は、スタイルの操作によって直接視覚的な変更を引き起こすことがよくありますが、データの検索や並べ替えなどの計算によって視覚的な変更が引き起こされる場合もあり、JavaScript の実行時間の遅さがパフォーマンスの問題の原因となる可能性があります。共通の原因とその影響を最小限に抑えるための努力が必要です。

JavaScript のパフォーマンス分析は芸術であると言えます。なぜなら、作成した JavaScript コードは、実際に実行されるコードとはまったく異なるからです。最新のブラウザは、JIT コンパイラとさまざまな最適化お​​よびトリックを使用して、可能な限り高速な実行を実現します。これにより、コードの動的な性質が大きく変わります。

アプリケーションが JavaScript を適切に実行するために役立ついくつかのこと:

  • アニメーション効果の場合は、setTimeout または setInterval の使用を避け、requestAnimationFrame を使用してください。

  • 長時間実行される JavaScript をメインスレッドから Web ワーカーに移動します。

  • 小さなタスクを使用して、複数のフレームにわたって DOM 変更を実行します。

  • Chrome DevTools のタイムラインと JavaScript プロファイラーを使用して、JavaScript の影響を評価します。

requestAnimationFrame を使用して視覚的な変化を実現します

画面が視覚的に変化するときは、フレームの先頭で操作を実行するのが最善です。フレームの開始時に JavaScript が実行されることを保証する唯一の方法は、requestAnimationFrame を使用することです。

/**
 * If run as a requestAnimationFrame callback, this
 * will be run at the start of the frame. */function updateScreen(time) {  // Make visual updates here.}
requestAnimationFrame(updateScreen);
ログイン後にコピー

フレームワークやサンプルでは、​​アニメーションなどの視覚的な変更を実行するために setTimeout または setInterval を使用することがありますが、このアプローチの問題は、コールバック関数がフレーム内の特定の時点 (おそらくフレームの最後) で実行されることです。これにより、フレームがドロップし、途切れが発生することがよくありました。 (コンポジットなどの js の実行には時間がかかり、UI の更新がブロックされます)。

実際、jQuery の現在のデフォルトのアニメーション動作は setTimeout を使用することです。requestAnimationFrame を使用するようにパッチを適用することを強くお勧めします。

複雑さを軽減するか、Web Worker を使用してください

JavaScript は、スタイルの計算、レイアウト、多くの場合描画とともにブラウザのメイン スレッドで実行されます。 JavaScript の実行時間が長すぎると、他の作業がブロックされ、フレーム落ちが発生する可能性があります。

したがって、JavaScript がいつ実行されるか、どのくらいの期間実行されるかを賢明に考慮してください。たとえば、スクロールなどのアニメーションを実行している場合、JavaScript を 3 ~ 4 ms の範囲内に保つ方法を見つけるのが最善です。これ以上の場合は時間がかかりすぎる可能性があります。時間が空いていれば、あまり時間を気にする必要はありません。

多くの場合、純粋な計算作業は Web ワーカーに移動できます。たとえば、DOM アクセス、データ操作、トラバース (並べ替えや検索など) を必要としないものは、読み込みやモデルの生成と同様に、このモデルによく適合します。 。

var dataSortWorker = new Worker("sort-worker.js?1.1.11");
dataSortWorker.postMesssage(dataToSort);// The main thread is now free to continue working on other things...dataSortWorker.addEventListener('message', function(evt) {   var sortedData = evt.data;   // Update data on screen...});
ログイン後にコピー

すべてのジョブがこのモデルに適しているわけではありません。Web ワーカーには DOM アクセス権がありません。操作をメイン スレッドで実行する必要がある場合は、大きなタスクを小さなタスクに分割し、それぞれのタスクにかかる時間は数ミリ秒以内で、フレームごとに requestAnimationFrame ハンドラー内で実行するバッチ アプローチを検討してください。

var taskList = breakBigTaskIntoMicroTasks(monsterTaskList);
requestAnimationFrame(processTaskList);function processTaskList(taskStartTime) {  var taskFinishTime;  do {// Assume the next task is pushed onto a stack.var nextTask = taskList.pop();// Process nextTask.    processTask(nextTask);// Go again if there’s enough time to do the next task.taskFinishTime = window.performance.now();
  } while (taskFinishTime - taskStartTime < 3);  if (taskList.length > 0)
    requestAnimationFrame(processTaskList);
}
ログイン後にコピー

このアプローチは UX と UI に影響を及ぼします。タスクが処理されていることをユーザーが確実に認識できるように、進行状況またはアクティビティ インジケーターを使用する必要があります。いかなる状況でも、このメソッドはアプリケーションのメイン スレッドを拘束せず、メイン スレッドがユーザーの操作に対して常に迅速に応答できるようにします。

JavaScriptの「フレーム税」を理解する

フレームワーク、ライブラリ、または独自のコードを評価するときは、JavaScript コードの実行のオーバーヘッドをフレームごとに必ず評価してください。これは、変換やスクロールなどのパフォーマンスが重要なアニメーション作業を実行する場合に特に重要です。

JavaScript のオーバーヘッドとパフォーマンスを測定する最良の方法は、Chrome DevTools を使用することです。通常、次のような単純なレコードが得られます。

メイン セクションには JavaScript 呼び出しのフレーム チャートが表示されるため、どの関数が呼び出されたか、それぞれにどれくらいの時間がかかったかを正確に分析できます

-JavaScript を実行すると、DevTools ユーザー インターフェイスの上部で JavaScript アナライザーを有効にすることができます:


この方法で JavaScript を分析するとオーバーヘッドが発生するため、JavaScript をより深く理解したい場合にのみ有効にしてください。ランタイム機能。このチェックボックスを有効にすると、同じアクションを実行できるようになり、JavaScript で呼び出される関数に関する詳細情報が得られます:

この情報を使用して、アプリケーションのパフォーマンスに対する JavaScript の影響を評価し、特定を開始できます。機能の実行に時間がかかりすぎるホットスポットを修正します。前に述べたように、長時間実行される JavaScript を削除するか、それが不可能な場合は Web ワーカーに移動して、メイン スレッドを解放して他のタスクの実行を継続する必要があります。

JavaScript のマイクロ最適化を避ける

要素の offsetTop をリクエストする方が getBoundingClientRect() を計算するよりも速いなど、ブラウザーが関数のあるバージョンを別のバージョンより 100 倍高速に実行することを知るのは素晴らしいことかもしれませんが、フレームごとに呼び出しています。このような関数の程度はほとんどの場合小さいです。したがって、JavaScript のパフォーマンスのこの側面に焦点を当てることは、無駄な労力になることがよくあります。通常、節約できるのは 10 分の数ミリ秒だけです。

ゲームや計算量の多いアプリケーションを開発している場合は、一般的に 1 つのフレームに多くの計算を入れることになるため、このガイドの例外となる可能性があります。その場合、さまざまな方法が役立ちます。

つまり、マイクロ最適化は、構築しているアプリの種類に対応していないことが多いため、慎重に使用してください。 2/8 ルールに従って、最初にボトルネックから最適化を開始します。

スタイル計算の範囲と複雑さを絞り込みます

要素の追加や削除、プロパティやクラスの変更、またはアニメーションを通じて DOM を変更すると、ブラウザで要素のスタイルが再計算され、多くの場合、ページも変更されます。またはレイアウトされるページの一部(つまり、自動的にリフローされます)。このプロセスは計算されたスタイルと呼ばれます 計算。

スタイルを計算する最初の部分は、一致するセレクターのセットを作成することです。これは基本的に、ブラウザーが特定の要素に適用するクラス、疑似セレクター、ID を判断することです。

2 番目の部分では、一致するセレクターからすべてのスタイル ルールを取得し、この要素の最終的なスタイルを決定します。 Blink (Chrome と Opera のレンダリング エンジン) では、これらのプロセスのオーバーヘッドは、少なくとも現時点ではほぼ同じです:

以前は時間の約 50% 要素の計算されたスタイルの計算はセレクターの一致に使用され、残りの時間の半分は一致ルールから RenderStyle (計算されたスタイル表現) を構築するために使用されます。

  • セレクターの複雑さを軽減します。BEM 仕様 (Block-Element_Modifer) などのクラス中心のアプローチを使用します。

  • スタイルを計算する必要がある要素の数を減らします。

セレクターの複雑さを軽減

最も単純なケースでは、CSS には要素のクラスが 1 つだけあります:

.title {
/* styles */
}

ただし、プロジェクトが成長するにつれて、より複雑な CSS を作成できるようになり、最終的にはセレクターは次のようになります:

.box:nth-last-child(-n+1) .title {
/* スタイル */
}

スタイルを適用する必要があるかどうかを知るために、ブラウザは実際に「これは、まさに負の N 番目の子にボックス クラスを持つ 1 つの要素を加えたものを親とするタイトル クラスを持つ要素ですか?」と尋ねる必要があります。 " "使用するセレクタと対応するブラウザによっては、この結果の計算にかなりの時間がかかる場合があります。特定のセレクターをクラスに変更できます:

.final-box-title {
/* styles */
}

開発者はクラスの名前に問題があるかもしれませんが、ブラウザにとって作業ははるかに簡単です。以前のバージョンでは、要素がそのタイプの最後の要素であるかどうかを知るために、ブラウザはまず他の要素に関するすべてを知る必要があり、それに続く要素が N 番目の最後の子になるかどうかを知る必要がありました。これは、単純に一致させるよりも高速でした。要素へのクラスセレクターははるかに高価です。

レンダー ツリーを生成するときは、DOM 要素ごとに、一致するセレクターがすべてのスタイル ルールで見つかり、対応するスタイル ルールがマージされる必要があります。
CSS セレクターは右から左に解析されるため、共通のスタイルが CSSOM ツリーの親ノードに配置され、より具体的なスタイル (セレクターがより具体的) が子ノードに配置され、ノードの数が決まります。ブランチとトラバースが減少します。 CSS ルールを読み取るために左から右の方法を使用すると、ほとんどのルールが最後まで不一致であることがわかり、右から左の方法を使用している間に多くの無駄な作業が行われることになります。右端のセレクターが一致しないことが判明した場合に限り、一致するものがあれば、多くの無効な一致を避けるために直接破棄します。

スタイルが計算される要素の数を減らす

パフォーマンスに関するもう 1 つの考慮事項、要素の変更時に計算する必要がある作業量は、多くのスタイル更新にとってより重要な要素です。

一般的に、計算されたスタイルを計算する最悪の場合のコストは、 要素は要素数とセレクター数を乗算したものです。 確認するには、各要素をすべてのスタイル ルールに対して少なくとも 1 回チェックする必要があります 一致する場合。

注: 以前は次のようでした: (たとえば) body 要素のクラスを変更した場合、ページのすべての子要素は計算されたスタイルを再計算する必要がありました。現在は少し異なります。変更時にスタイルが再計算される要素の場合、ブラウザによっては、そのような要素ごとに固有の小さなルール セットが維持されます。これは、ツリー内の要素の位置と変更された特定のプロパティによっては、要素を必ずしも再計算する必要がないことを意味します。

スタイル計算は、ページ全体を無効と宣言するのではなく、少数のターゲット要素に向けられることがよくあります。最近のブラウザでは、変更が影響する可能性のあるすべての要素を必ずしもチェックする必要がないため、これはあまり問題になりません。一方、古いブラウザは必ずしもそのようなタスクに対して最適化されているわけではありません。無効として宣言された要素の数は可能な限り減らす必要があります

注: Web コンポーネントに興味がある場合は、デフォルトではスタイルが Shadow DOM の境界を越えず、ツリー全体ではなく単一のコンポーネントにスコープされるため、この点でスタイルの計算が若干異なることに注意する価値があります。 。ただし、全体としては、同じ概念が依然として当てはまります。単純なルールを持つ小さなツリーは、より複雑なルールを持つ大きなツリーよりも効率的に処理されます。

スタイル再計算のコストの測定

スタイル再計算を測定する最も簡単で最良の方法は、Chrome DevTools のタイムライン モードを使用することです。まず、DevTools を開き、[タイムライン] タブに移動し、[記録] を選択して Web サイトを操作します。記録を停止すると、次の図に示す状況が表示されます。

上部のバーは 1 秒あたりのフレーム数を表し、バーが下の線 (60fps の線) を超えている場合は、長時間実行されているフレームがあります。


スクロールやその他のインタラクションなどの一部のインタラクションに長時間実行フレームがある場合、これをさらに見直す必要があります。

上記の例に示すように、大きな紫色のブロックが表示された場合は、「記録」をクリックして詳細を確認してください。

このクロールでは、18 ミリ秒強かかる長時間実行の再計算スタイル イベントがあり、スクロール中に偶然発生し、ユーザーに顕著なジッターを経験させます。

イベント自体をクリックすると、スタイル変更をトリガーした JavaScript 内のポイントを正確に示す呼び出しスタックが表示されます。さらに、スタイルが変更によって影響を受ける要素の数 (この場合は 400 を少し超える要素) と、スタイルの計算に要した時間も取得します。この情報を使用して、コード内の修正点の検索を開始できます。

BEM仕様を使用

BEM のコーディング アプローチには、すべての要素に対して単一のクラスを推奨し、階層が必要な場合にはクラスの名前も組み込むため、上記で説明したセレクター マッチングのパフォーマンス上の利点が実際に組み込まれています:

.list { }
。 -item { }

上記のように、最後の子要素に対して特別な処理を行いたいなど、修飾子が必要な場合は、次のように追加できます:

.list__list-item--last-child {}

CSS を整理する良い方法を探している場合、BEM は構造的な観点からだけでなく、スタイルの検索が簡素化されるため、始めるのに最適な場所です。

大規模で複雑なレイアウトとレイアウトのジッターを回避します

レイアウトとは、ブラウザーが各要素の幾何学的情報 (ページ上のサイズと位置) を計算するプロセスです。 各要素は、使用される CSS、要素のコンテンツ、またはその親要素に応じて、明示的または暗黙的なサイズ情報を持ちます。このプロセスは、Chrome、Opera、Safari、Internet Explorer ではレイアウトと呼ばれます。 Firefoxでは自動リフロー(Reflow)と呼ばれていますが、実際には同じプロセスです。

スタイルの計算と同様に、レイアウトのオーバーヘッドに関する直接的な考慮事項は次のとおりです:

  1. レイアウトする必要がある要素の数。

  2. これらのレイアウトの複雑さ。

  • レイアウトの範囲は通常、ドキュメント全体です。

  • DOM 要素の数はパフォーマンスに影響を与えるため、レイアウトのトリガーは可能な限り回避する必要があります。

  • レイアウト モデルのパフォーマンスを評価します。新しい Flexbox は、古い Flexbox または float ベースのレイアウト モデルより高速です。

  • 強制的な同期レイアウトやレイアウトのスラッシングを避けてください。 スタイル値を読み取り、スタイルを変更します。

レイアウト操作をできる限り避けてください

スタイルを変更するとき、ブラウザは、変更にレイアウト計算が必要かどうか、およびレンダー ツリーを更新する必要があるかどうかを確認します。 幾何学的プロパティ(幅、高さ、左または上など)への変更はすべてレイアウト計算が必要です。

.box {

幅: 20px;
高さ: 20px;
}
/**変化 幅と高さによってレイアウトがトリガーされます。 */
.box--expanded {
幅: 200px;
高さ: 350px;
}

レイアウトほとんどの場合、文書全体に影響します。 要素の数が多い場合、すべての要素の位置とサイズを把握するのに時間がかかります。

レイアウトを回避できない場合、重要なのは、Chrome DevTools を使用してレイアウトにかかる時間を確認し、レイアウトがボトルネックの原因であるかどうかを判断することです。まず、DevTools を開き、[タイムライン] タブを選択し、[記録] ボタンをクリックして、Web サイトを操作します。記録を停止すると、サイトのパフォーマンスの詳細な分析が表示されます:

上の例のフレームをよく見ると、レイアウトに 20 ミリ秒以上費やされていることがわかります。アニメーションでは 16 ミリ秒 このレイアウトでは、画面にフレームを表示するのに時間がかかりすぎます。また、DevTools がツリーのサイズ (この場合は 1618 要素) とレイアウトする必要があるノードの数を示すこともわかります。

古いレイアウト モデルの代わりにフレックスボックスを使用します

Web ページにはさまざまなレイアウト モデルがあり、一部のモードは他のモードよりも広くサポートされています。初期の CSS レイアウト モデルでは、絶対的、絶対的、またはフローティング要素を基準にして画面上に要素を配置することができました。

以下のスクリーンショットは、1,300 個のボックスでフロートを使用した場合のレイアウトのオーバーヘッドを示しています。もちろん、ほとんどのアプリケーションはさまざまな手段を使用して要素を配置するため、これは不自然な例です。

Flexbox (Web プラットフォームの新しいモデル) を使用するようにこの例を更新すると、別の状況が現れます:

さて、同じ数の要素と同じ外観の場合、レイアウト時間は大幅に短縮されます (この場合はそれぞれ 3.5 ミリ秒と 14 ミリ秒)。場合によっては、Flexbox はフロートほどサポートされていないため、選択肢にならない可能性があることを覚えておくことが重要です。ただし、可能であれば、少なくとも Web サイトのパフォーマンスに対するレイアウト モデルの影響を調査し、実行オーバーヘッドを最小限に抑えるモデルを採用する必要があります。ウェブページ。

いずれの場合も、Flexbox を選択するかどうかに関係なく、アプリケーションのストレスが高い時点では、

レイアウトをまったくトリガーしないようにする必要があります !

レイアウトの強制的な同期を避ける

将一帧送到屏幕会采用如下顺序:

 

首先 JavaScript 运行,然后计算样式,然后布局。但是,JavaScript 在更改元素样式后,获取其几何属性的值,此时会强制浏览器应用新样式提前执行布局,值后才能获取几何属性值。这被称为强制同步布局(forced synchronous layout

要记住的第一件事是,在 JavaScript 运行时,来自上一帧的所有旧布局值是已知的,并且可供您查询。因此,如果(例如)您要在帧的开头写出一个元素(让我们称其为“框”)的高度,可能编写一些如下代码:

// Schedule our function to run at the start of the frame.requestAnimationFrame(logBoxHeight);function logBoxHeight() {  // Gets the height of the box in pixels and logs it out.  console.log(box.offsetHeight);
}
ログイン後にコピー

如果在请求此框的高度之前,已更改其样式,就会出现问题:

function logBoxHeight() {
  box.classList.add('super-big');    //样式更改后,浏览器必须先应用新的样式(重绘)之后才能获取当前的值,有时是多做无用功
  // Gets the height of the box in pixels and logs it out.  console.log(box.offsetHeight);
}
ログイン後にコピー

现在,为了获得框的高度,浏览器必须先应用样式更改(由于增加了 super-big 类),然后运行布局,这时才能返回正确的高度。这是不必要的,并且可能开销很大。

因此,始终应先批量读取样式并执行(浏览器可以使用上一帧的布局值),然后执行任何赋值操作。

以上函数应为:

function logBoxHeight() {  // Gets the height of the box in pixels and logs it out.  console.log(box.offsetHeight);
  box.classList.add('super-big');
}
ログイン後にコピー

大部分情况下,并不需要先应用新样式然后查询值,使用上一帧的值就足够了。与浏览器同步(或比其提前)运行样式计算和布局可能成为瓶颈。

避免布局超负荷(thrashing)

有一种方式会使强制同步布局更糟:连续执行大量这种强制布局。如下:

function resizeAllParagraphsToMatchBlockWidth() {  // Puts the browser into a read-write-read-write cycle.
  for (var i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = box.offsetWidth + 'px';
  }
}
ログイン後にコピー

此代码循环处理一组段落,并设置每个段落的宽度以匹配一个称为“box”的元素的宽度。这看起来没有害处,但问题是循环的每次迭代读取一个样式值 (box.offsetWidth),然后立即使用此值来更新段落的宽度 (paragraphs[i].style.width)。在循环的下次迭代时,浏览器必须考虑样式已更改这一事实,因为 offsetWidth 是上次请求的(在上一次迭代中),所以它必须应用更改的样式,然后运行布局。每次迭代都将出现此问题!

此示例的修正方法还是先读取值,然后写入值:

// Read.var width = box.offsetWidth;function resizeAllParagraphsToMatchBlockWidth() {  for (var i = 0; i < paragraphs.length; i++) {// Now write.paragraphs[i].style.width = width + 'px';
  }
}
ログイン後にコピー

如果要保证安全,应当查看 FastDOM,它会自动批处理读取和写入,应当能防止意外触发强制同步布局或布局抖动。

简化绘制的复杂度、减小绘制区域

绘制是填充像素的过程,像素最终合成到用户的屏幕上。 它往往是管道中运行时间最长的任务,应尽可能避免此任务。

  • 除 transform 或 opacity 属性之外,更改任何属性始终都会触发绘制。

  • 绘制通常是像素管道中开销最大的部分,应尽可能避免绘制。

  • 通过layer promotion和动画的编排来减少绘制区域。

  • 使用 Chrome DevTools paint profile来评估绘制的复杂性和开销;应尽可能降低复杂性并减少开销。

触发布局与绘制

如果触发布局,则总是会触发绘制,因为更改任何元素的几何属性意味着其像素需要修正!

 

如果更改非几何属性,例如背景、文本或阴影,也可能触发绘制。在这些情况下,不需要布局,并且管道将如下所示:

 

使用 Chrome DevTools 快速确定绘制瓶颈

Chrome DevTools を使用すると、描画している領域をすばやく決定できます。 DevTools を開き、キーボードの Esc キーを押します。表示されるパネルで「レンダリング」タブに移動し、「ペイント長方形を表示」にチェックを入れます。

このオプションをオンにすると、Chrome は描画が行われるたびに画面を緑色に点滅させます。画面全体が緑色に点滅している場合、または描画すべきではない画面領域が表示されている場合は、さらに調査する必要があります。

Chrome DevTools タイムラインには、詳細情報を提供するオプションがあります: Draw Profiler。このオプションを有効にするには、タイムラインに移動し、上部の「ペイント」ボックスにチェックを入れます。注意として、オーバーヘッドが発生し、プロファイリング結果に影響を与える可能性があるため、このオプションは描画の問題を解析する場合にのみオンにしてください。何が描かれているのかをより深く理解したい場合に最適です。

上記の設定を完了すると、タイムライン記録を実行できるようになり、描画記録に詳細が含まれるようになります。フレームの描画レコードをクリックすると、そのフレームの描画アナライザーが表示されます:

描画アナライザーをクリックすると、どの要素が描画されたか、どのくらいの時間がかかったか、何が描画されたかを確認できるビューが表示されます。必須 個別の描画呼び出し:

このプロファイラーは、領域と複雑さ (事実上、描画にかかった時間) を表示します。描画を回避できない場合は、どちらも管理できます。

移動した要素や色褪せた要素を強調する

描画は常にメモリ内の単一の画像に描画されるわけではありません。実際、ブラウザは必要に応じて複数の画像またはコンポジタ レイヤーを描画できます。

この方法の利点は、定期的に再描画されたり、変換によって画面上で移動される要素を、他の要素に影響を与えることなく処理できることです。 Sketch、GIMP、Photoshop などのアート ファイルにも同様のことが当てはまり、個々のレイヤーを処理して重ね合わせて最終画像を作成できます。

新しいレイヤーを作成する最良の方法は、will-change CSS プロパティを使用することです。このメソッドは Chrome、Opera、Firefox で動作し、transform の値を渡すと新しいコンポジター層が作成されます:

.movi​​ng-element {
will-change:transform;
}

will-change の場合はサポートされていませんが、 Safari や Mobile Safari など、レイヤー作成の恩恵を受けるブラウザでは、3D 変換を使用して新しいレイヤーを強制的に作成する必要があります。注意: 各レイヤーにはメモリと管理オーバーヘッドが必要となるため、レイヤーを作成しすぎないでください。

要素を新しいレイヤーにプロモートした場合は、DevTools を使用して、それによってパフォーマンスが向上することを確認してください。
要素を分析せずに宣伝しないでください。

描画領域を減らす

ただし、要素が改善されても描画作業が必要な場合があります。描画の問題に関する大きな課題は、ブラウザが描画する必要がある 2 つの領域を結合し、これにより画面全体が再描画される可能性があることです。したがって、ページの上部に固定ヘッダーがあり、画面の下部に要素が描画されている場合、画面全体が再描画される可能性があります。

描画領域を減らすということは、多くの場合、アニメーションと変形が重なりすぎないように配置したり、ページの特定の部分がアニメーション化されないようにすることを意味します。

描画の複雑さを軽減

描画に関しては、一部の図面は他の図面よりも高価です。たとえば、ぼかしを伴う要素 (影など) を描画すると、赤いボックスを描画するよりも時間がかかります。ただし、これは CSS: 背景: red および box-shadow: 0、4px、4px では必ずしも明らかではありません。 rgba(0,0,0,0.5); は必ずしも完全に異なるパフォーマンス特性を持っているようには見えませんが、実際には異なります。

上記の描画アナライザーを使用すると、効果を達成するために他の方法を探す必要があるかどうかを判断できます。より安価なスタイルのセットや別の方法を使用して最終結果を達成することが可能かどうかを自問してください。

特にアニメーション効果では、描画をできるだけ避けたいと考えています。なぜなら、フレームごとに

10

ms

という時間予算では、特にモバイル デバイスでは、通常、描画作業を完了するには十分ではないからです。

以上がブラウザのレンダリングパフォーマンスの最適化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート