😽

Webのレンダリングの仕組みについて

2021/03/08に公開

Webフロントエンドハイパフォーマンスチューニングという本を読んでいます。
自分の知らないブラウザ周りの知識が多くてかなり勉強になるのですが、
解説が豊富すぎて整理しておきたいので、自分がわかりやすいようにまとめます。

2章 レンダリングの仕組み

レンダリングを知ることのメリット

1. コーディングをするとき、パフォーマンスの問題となる書き方を未然に避けることができる
2. パフォーマンスの問題が起きているとき、どこがボトルネックかを推測しやすくなる
3. パフォーマンスを測定するとき、プロファイル結果を見てどこがボトルネックになっているか理解できるようになる
4. パフォーマンスを最適化するとき、どのチューニングテクニックがそのボトルネックに対して適切か判断できるようになる

エンジンについて

ブラウザはいくつかのコンポーネントから構成される
パフォーマンスチューニングの観点で押さえていおきたいのはこの2つ

1. レンダリングエンジン
2. JavaScriptエンジン

解説を加えると、

1. レンダリングエンジン (Blink, WebKit, Gecko...)
  HTMLの描画(=レンダリング)をする
  => HTML, CSS, JS, 画像などを読み取り、画面上に実際に表示する

2. JavaScriptエンジン(V8, Chakra, ...)
  JavaScriptの実行環境を提供する
  => DOMツリーやCSSOMツリー内部のドキュメントやAPIをJSで操作できるようにしてくれる

レンダリングの流れについて

ブラウザがレンダリング(描画)するまでの流れは下記となる

1. Loading(リソース読み込み)
2. Scripting(JS実行)
3. Rendering(レイアウト計算)
4. Painting(計算結果の描画)

それぞれの工程はさらに細分化される

1. Loading(リソース読み込み)
     Download
     Parse
2. Scripting(JS実行)
3. Rendering(レイアウト計算)
     Calculate
     Style
4. Painting(計算結果の描画)
     Paint
     Rasterize
     Composite Layers


1. Loading(リソース読み込み)

1. Loading(リソース読み込み)
     Download
     Parse

【結局、何をしているのか】

HTMLをダウンロードして、HTML => 内部表現(DOMツリーなど)への変換を行う
(内部表現: そのレンダリングエンジンがHTMLを描画するために必要な情報のこと)

ブラウザはHTMLを描画しているのではなく、HTMLやCSSから変換されたDOMツリー、CSSOMツリーを描画している


【処理の流れ】

1. ブラウザがサーバにリクエストを送る
2. ブラウザはサーバからレスポンスを受け取る
   => レスポンスに含まれるもの:HTML, CSS, JS, 画像など
  
3. 最初にHTMLを取得し(Download)、解析・変換(Parse)を行う
   => レンダリングエンジンは、取得したHTMLを読み込みながらDOMツリーを構築していく
4. HTMLの読み込み途中でCSSや画像(=リソース)が参照されていたら、その都度取得して読み込む
   => その過程で、CSSはCSSOMツリーに変換され、画像やJSなどのリソースも内部表現に変換される

つまり、HTMLを元にDOMツリーを構築しながら、必要があればCSSやJSを取得して読み込むということ

【補足】

1. この時点では、まだ描画されていない。描画は4. Paintingの工程で行う
2. DOMツリー、CSSOMツリーはレンダリングエンジンの内部表現だが、これらをJavaScriptで
   操作できるようにしたのが前述したJavaScriptエンジン

1点注意するべきは、DOMツリー構築中に参照ファイルを読み込むので、
CSSやJSが重いと構築が中断され、構築にかかる時間が増える


ここまでのまとめ

1. Loading(リソース読み込み)
     HTMLなどのリソースを取得・解析し、内部表現への変換を行う
2. Scripting(JS実行)
3. Rendering(レイアウト計算)
4. Painting(計算結果の描画)


2.Scripting(JSの実行)

2. Scripting(JS実行)

【結局、何をしているのか】

JavaScriptのコードを、JavaScriptエンジンが読めるコードに変換し、実行する

僕らが読んでいるJavaScriptのコードは、JavaScriptエンジンは読めないので、読み込める形(機械語)に変換する
=> この変換をコンパイルという

【処理の流れ】

1.【解析・コンパイル】
JavaScriptのコード
↓ 
↓ 字句解析
↓ 
トークン
↓ 
↓ 構文解析
↓ 
抽象構文木
↓ 
↓ コンパイル
↓ 
JavaScriptエンジンが実行可能なコード

2.【JSを実行】

【コンパイルについて】

何にコンパイルされるかは、JavaScriptエンジンがどのように
JSを実行したいかというエンジン側の内部実装によって決まる

【どのようなコンパイルがあるか】
1. 仮想マシン型のコンパイル
2. JIT(Just In Time)型のコンパイル

【何がJSを実行するか】
1. 仮想マシン型 => 仮想マシン
2. JIT型 => CPU

【何に変換されるか】
1. 仮想マシン型 => 仮想マシンが実行できるコード
2. JIT型 => CPUが解釈できる機械語

ちなみに

【JITとAOT】
1. JIT(Just In Time) => コード実行時にコンパイル
2. AOT(Ahead Of Time) => コード実行前にコンパイル、JavaやTSのコンパイルはこれ


ここまでのまとめ

1. Loading(リソース読み込み)
     HTMLなどのリソースを取得・解析し、内部表現への変換を行う
2. Scripting(JS実行)
     JSのコードをJSエンジンが実行できる形に解析・コンパイルして実行
3. Rendering(レイアウト計算)
4. Painting(計算結果の描画)


3. Rendering(レイアウト計算)

3. Rendering(レイアウト計算)
     Calculate
     Style

【結局、何をしているのか】

DOMツリーとCSSOMツリーから、どの要素にどのCSSが当たるかを計算し、空間的なレイアウトを決める

それぞれの工程についても載せます。

1. Calculate
  DOMツリーとCSSOMツリーから、どの要素にどのCSSが当たるかを計算する
  
2. Style
  1.で計算した結果から、空間的なレイアウト情報を計算する

【処理の詳細】

3. Rendering
  1. Calculate
     DOMツリーとCSSOMツリーの情報から、ある要素に適用されるスタイルルールを決定する
       a. 総当りでマッチングされる
         DOM要素が50個、スタイルルールが300個ある場合、50 * 300 = 15,000回のマッチングが発生する
       b. 詳細度によるルールの決定もここで行われる
         詳細度(MDN) => https://developer.mozilla.org/ja/docs/Web/CSS/Specificity
         
  2. Style
     空間的な位置情報にあたるルールだけを計算して、空間的レイアウトを決める
     (height/width,, margin, padding, z-indexなどのみ計算)


ここまでのまとめ

1. Loading(リソース読み込み)
     HTMLなどのリソースを取得・解析し、内部表現への変換を行う
2. Scripting(JS実行)
     JSのコードをJSエンジンが実行できる形に解析・コンパイルして実行
3. Rendering(レイアウト計算)
     DOMツリーとCSSOMツリーから、どの要素にどのCSSが当たるかを計算し、空間的なレイアウトを決める
4. Painting(計算結果の描画)


4. Painting(計算結果の描画)

4. Painting(計算結果の描画)
     Paint
     Rasterize
     Composite Layers

【結局、何をしているのか】

レイヤーの生成・合成によりレンダリングする画面を決定し、レンダリングする

それぞれの工程についても載せます。

4. Painting(計算結果の描画)
   Paint
     2Dグラフィックエンジン向けの命令を作成
   Rasterize
     命令を用いてピクセル(ビットマップ)を作成し、レイヤーとして描画
   Composite Layers
     レイヤーを合成して、レンダリング結果を決定

【処理の詳細】

4. Painting(計算結果の描画)
   Paint
    省略(上記とほぼ同じ)
   Rasterize
     命令を用いてピクセル(ビットマップ)を作成し、レイヤーとして描画
     => 後々再計算しなくていいように(=再利用できるように)レイヤーとしてもっておく
     それぞれのレイヤーはz軸方向の位置関係(z-index)も持ち合わせている
   Composite Layers
     レイヤーを合成して、レンダリングする画面を決定


ここまでのまとめ

1. Loading(リソース読み込み)
    HTMLなどのリソースを取得・解析し、内部表現への変換を行う
2. Scripting(JS実行)
    JSのコードをJSエンジンが実行できる形に解析・コンパイルして実行
3. Rendering(レイアウト計算)
    DOMツリーとCSSOMツリーから、どの要素にどのCSSが当たるかを計算し、空間的なレイアウトを決める
4. Painting(計算結果の描画)
    レイヤーの生成・合成によりレンダリングする画面を決定し、レンダリングする


再レンダリングについて

再レンダリング=最初からレンダリングをやり直し、ではない
ブラウザ側でどのような操作をしたかによって、再実行される工程が変わる
(場合によっては、複数の工程が再実行される)

ex) DOMを操作すると画面表示が変わるのでRendering or Layoutからやり直しになる






[引用]
第2章 レンダリングの仕組み
(Webフロントエンドハイパフォーマンスチューニング/久保田光則 著/技術評論社)

Discussion