ブラウザのページレンダリングプロセス
HTML解析プロセス
通常の状況では、サーバーは xx.html ファイルをブラウザに返しますが、HTML の解析は実際には Dom ツリーの構築プロセスです。
次の HTML 構造に基づいて HTML 解析プロセスを簡単に分析できます。
CSS ルール ツリーを解析する
解析プロセス中に CSS リンク要素が見つかった場合、ブラウザーは対応する CSS ファイルをダウンロードします。
PS: ここで CSS をダウンロードしても、DOM ツリーの解析には影響しません。
ダウンロードが完了すると、CSS ファイルが解析され、対応するルール ツリーが解析されます。例は次のとおりです。
body{
font-size: 16px}
p{
font-weight: bold}
span{
color: red}
p span{
display:none}
img{
float: right}
レンダー ツリーを構築するための解析ステップ
DOM ツリーと CSSOM ツリーを取得したら、その 2 つを組み合わせてレンダー ツリーを構築できます。
注意しなければならないことは次のとおりです。
- link 要素は DOM ツリー構築プロセスをブロックしませんが、レンダー ツリー構築プロセスをブロックします。
- Render Tree と DOM Tree には 1 対 1 の対応関係はありません。たとえば、表示が none に設定されている要素は Render Tree にまったく表示されません。
ステップのレイアウトと描画を解析する
- レンダー ツリーでレイアウトを実行して、各ノードのジオメトリを計算します。
- レンダリング ツリーは、表示されるノードとその他のスタイルを示しますが、各ノードのサイズ、位置、その他の情報は示しません。
- レイアウトは、レンダリング ツリー内のすべてのノードの幅、高さ、および位置情報を決定します。
- 各ノードを画面に描画します
- 描画フェーズでは、ブラウザはレイアウト フェーズで計算された各フレームを画面上の実際のピクセルに変換します。
- テキスト、色、境界線、影、置換要素 (img など) などの要素の表示部分の描画を含みます。
レンダリング プロセスについては、次の図を参照してください。
上記の 5 つの手順を完了すると、対応する xx.html ファイルがブラウザで正常にレンダリングされます。
リフローと再描画
リフロー
reflow
:
- レンダリングするノードのサイズと位置は、レイアウト中の最初のレンダリング後に決定されます。
- その後のノードのサイズと位置の再計算はリフローと呼ばれます。
リフローが発生する場合:
- DOM 構造の変更 (追加と削除)
- CSSのスタイルコード、つまりレイアウトを変更しました。
- 変更されたウィンドウサイズ
- または、位置とサイズの情報を取得するためにいくつかの組み込み関数が呼び出されます。
再版
- 初めてレンダリングするとき、前のフローチャートで が呼び出されました。印刷
- 後で再レンダリングする必要がある場合は、再描画になります。
再描画が行われる仕組み:
- カラーテキストスタイルなどのCSSを変更する
アイデアを広げる
- リフローが発生する限り、必ず再描画が発生しますが、実際、上記の説明を見ると、スタイル コードの開始時や変更時にもリフローが発生することが容易にわかります。
- リフローのパフォーマンスは良くなく、DOM 全体を再レンダリングするのはパフォーマンスの無駄であることは明らかです。
要約する
- スタイルを変更してリフローの回数をできる限り減らす、つまりデザイン完了後は、必要な場合以外はスタイルや DOM 構造を変更しないでください。
- DOM を操作するために JS を頻繁に使用することは避けてください。
- 保存場所情報を取得する機能を最小限に抑える
特殊解析・複合合成
描画プロセス中に、レイアウトされた要素を複数の複合レイヤーに描画できます。
新しい合成レイヤーを形成するプロパティ:
- 3D 変換
- ビデオ、キャンバス、iframe
- 不透明度アニメーションの変換
- 位置: 固定
- 変更されます
- アニメーションまたはトランジションには不透明度とトランスフォーム セットが含まれています
PS: 階層化により確かにパフォーマンスが向上しますが、メモリ管理が犠牲になるため、パフォーマンスの最適化戦略としては使用されません。
スクリプト要素とページ解析の関係
JS はレンダリング プロセスでどのようなステップを実行しますか?
- HTML をレンダリングするとき、js には DOM の構築を続行する機能がありません。
- 必要な部分が必要な場合は一旦構築を中止し、jsをダウンロードしてスクリプトを実行します。
- 構築する必要があるものを構築したら、DOM の構築を続けます。
これを行うことでどのようなメリットがあるのでしょうか?
- JSにはDOMを操作・変更する機能があります
- なぜ最初に js スクリプトを実行するのでしょうか? 前述したように、リフローはパフォーマンスに非常に負荷がかかるため、不必要なリフローを減らすために一度に実行するのが最善です。
コード例
index.html
<script src="./js/test.js"></script>
<body>
<div class="box"></div>
</body>
<script>
var boxel = document.getElementsByClassName("box")
console.log(boxel);
</script>
test.js
debugger
console.log("hello")
新しい質問:
- 現在の開発モデルでは開発フレームワークとしてvueやReactを使用することが多く、JSの割合が多くイベントの処理にも時間がかかります。
- また、これにより、解析がブロックされると、スクリプトの解析が完了するまでインターフェイスに何も表示されなくなる可能性があります。
ここで、js はこの問題を解決するために 2 つの属性を提供します
遅延属性
defer 属性は、ブラウザにスクリプトのダウンロードを待たずに、HTML の解析と DOM ツリーの構築を続行するように指示します。スクリプトが事前にダウンロードされている場合は、ロードを待ちます。DOM が完了したら、defer 内のコードを実行します。 DOMContentLoaded をトリガーする前。
PS: defer は順序に影響を与えることなくデフォルトの順序で実行され、DOM を操作できます
<script>
window.addEventListener("DOMContentLoaded", () => {
console.log("DOMContentLoaded");
})
</script>
<script>
var boxel = document.getElementsByClassName("box")
console.log(boxel);
</script>
<script defer>
console.log("defer-demo")
</script>
<script>
debugger
console.log("hello")
</script>
提案:
- 先頭に defer を入れて、最後にこの属性の特性を使用するのは本末転倒です。
- defer は外部スクリプトにのみ影響します
非同期属性
非同期機能は defer に似ており、スクリプトがページをブロックしないようにすることもできます。
その特徴:
- ブラウザーは非同期スクリプトをブロックしません (遅延と同様)。
- 非同期スクリプトは順序を保証できません。非同期スクリプトは個別にダウンロードされて実行され、他のスクリプトを待ちません。
- async は DOMContentLoaded の前後で実行されることは保証されていません
<script>
window.addEventListener("DOMContentLoaded", () => {
console.log("DOMContentLoaded");
})
</script>
<script async>
console.log("defer-demo")
</script>
要約する
- defer は通常、ドキュメントの解析と、DOM を操作し順序要件のある JS コードに使用されます。
- async は通常、依存関係のない独立したスクリプトに使用されますが、依存関係がある場合、事前に読み込まれるという保証はありません。
要約する
- まず、いくつかのブラウザカーネルを理解して理解します
- サーバーの読み込みからページのレンダリングまでの流れを理解する
- 各ステップの一般的な内容を詳しく説明します
- 問題を発見し、それに対するいくつかの解決策を検討しました