ブラウザのレンダリングの仕組み
「ブラウザを立ち上げてアドレスバーにURLを打ち込んでEnter押してからページが表示されるまでに (裏側で) 何が起こっているかわかる限り説明してみてください。」
っていう問題を先輩から出題されたのですが、上手く答えられず...
ブラウザのレンダリングについてWebフロントエンド ハイパフォーマンス チューニングを読んで勉強したのでそのmemoです。
1. レンダリングエンジン
ブラウザ | レンダリングエンジン | JavaScriptエンジン |
---|---|---|
Google Chrome | Blink | V8 |
IE | Trident | Chakra |
Microsoft Edge | EdgeHTML | Chakra |
Firefox | Gecko | SpiderMonkey |
Safari | Webkit | Nitro(JavaScriptCore) |
Blink,WebKit,Geckoはオープンソースのレンダリングエンジン。 BlinkはWebKitをフォークして誕生。
ブラウザ内のコンポーネント
いくつかのソフトウェアコンポーネントによって構成されている。
知っておきたい2つの重要なコンポーネントは以下。
- レンダリングエンジン
- JavaScriptエンジン
レンダリングエンジンとは?
- HTMLの描画エンジン。
- Webページのレンダリングのみを担当。
- HTMLや画像ファイルやCSS、JavaScriptなどを読み取り画面上の実際のピクセルとして描画する。
JavaScriptエンジンとは?
- JavaScriptの実行環境を提供するソフトウェアコンポーネント。
- DOMツリー、CSSOMツリーなど内部のオブジェクト、APIに対してJavaScriptからアクセスできるようにバインディングを提供。
- ブラウザの拡張機能を実行するために利用される
CSSOMとは?
CSSOMは、CSS Object Modelを意味する略語であり、ブラウザでロードされたCSSのツリー構造を保持する仕組み。ブラウザは、このCSSのツリー構造をDOMに対して適用することで、上位のスタイルからより具体的な下位のスタイルへと連鎖的にスタイルを決定していく。
2. ブラウザのレンダリングの流れ
レンダリングの大まかな流れ
Loading(リソース読み込み)
↓
Scripting(JavaScript実行)
↓
Rendering(レイアウトツリー構築)
↓
Painting(レンダリング結果の描画)
4つの工程からレンダリングが始まって、最終的に描画されるまでをフレーム(Frame)と呼ぶ。
3. リソース読み込み
まず行われるのがリソース読み込み
ブラウザは、与えられたURLからHTMLを読み込んで、そこからさらにレンダリングに必要な付属するリソースを読み込んで解釈する このフェーズでは、次の2つの処理がある。
- リソースのダウンロード
- HTMLを含むリソースをサーバーからダウンロードする。
- リソースのパース
リソース
- HTMLファイル
- CSSファイル
- JS画像ファイル
3.1 リソース取得に用いるネットワークプロトコル
ブラウザは与えられたURLをもとにレンダリングをもとにレンダリングに必要なリソースを様々なネットワークプロトコルを通じて取得する。
ブラウザでよく利用されるネットワークプロトコルはHTTP
- URLに含まれるホスト名の解決
- HTTPによる取得
IP(Internet Protocol)
ネットワークのノード間のパケットのやり取りを中継するプロトコル。
HTTPでネットワーク越しにリソースを取得する場合、リソースの取得の速さはIPのパケットの届く速度に依存する。 →HTTPでやり取りされるデータパケット内に格納されるから。
パケット データの通信に利用される最小単位のデータ。 通信するデータの入れ物としてやり取りされる
TCP(Transmission Control Protocol)
TCPは、IPに対して以下のような機能を付加する上位プロトコル
- 相手先に確実にデータが届いているかどうか確認
- データの欠損や破損をけんちして再送
- データの送信順を保証する
TLS(Transport Layer Security)
与えられたURLのプロトコル部分がhttpsだった場合TCPとHTTPの間でTLSプロトコルを利用する。 TLSは一般にSSLと呼ばれる。
- クライアントとサーバーの認証機能
- 通信データの暗号化
- データの改ざんの検出
UDP (User Datagram Protocol)
IPに対して機能を付加。 TCPと似ている。 TCPプロトコルは、IPに対してデータの欠損の検知やデータの送信順の保証などにお信頼性のあるデータ通信を提供するがUDPではそのような機能は特に追加しない。
HTTP
DNS(Domain Name System)
TCP接続では、接続を開始するのに相手方のIPアドレスが必要。 ブラウザはURLに含まれているホスト名をIPアドレスに変換した上でHTTPリクエストをサーバーへと送信する。
DNSはホスト名に紐づくIPアドレスを検索するための分散システム。
4. それぞれのリソースの読み込み
ブラウザはホスト名の解決などを経て、HTML,CSS,JacaScriptや画像といったリソースを取得する。
一番最初に読み込まれるリソースはHTMLファイル。
- HTMLファイル内に記述されているリソースの参照があれば、さらにそのリソースを読み込む。
- 取得したリソースは、パースされてブラウザの内部表現に変換される。
HTMLの読み込み
- ブラウザは与えられたウェブページのURLを元にサーバーへHTTPリクエストを送信。 HTTPレスポンスとしてHTMLを取得する。
- 読み込んだHTMLを解釈してドキュメントのDOMツリーを構築する。DOMツリーへの変換過程の中でツリーに含まれる画像やCSSなどのドキュメントに紐づくリソースに取得や読み込みを行う。
- ブラウザは構築したDOMツリーを元にしてRenderingの処理を行う。
DOM(Document Object Model)
HTMLのドキュメントを表現するオブジェクト。 DOMツリーは、レンダリングエンジンが利用する木構造を持つ内部表現。
DOMツリーへの変換の工程
- 字句解析によるトークンのリスト化
- 構文解析による構文木構築
- 構文木内にあるJavaScriptを実行しつつDOMツリーの構築
字句解析
コンパイラーがソースコードを解析し、目的のプログラムを生成する際の処理工程のひとつ。字句解析は、ソースコードに記述された変数や定数などの値を実際の値に展開するまでを担当し、その結果を次の工程である構文解析に引きわたす。
トークン
1つの塊になっている文字列
CSSの読み込み
読み込まれたCSSは、レンダリングエンジンによってパースされてCSSOM(CSS Object Model)ツリーへと変換される。
DOMツリーと違ってCSSOMツリーの深さは可変ではなく、一定ですが、ルールセットが増えれば増えるほどDOMツリー内の要素に適用されるスタイル計算にかかる時間が大きくなる。
5. JavaScript実行 Scripting
リソースを一式読み込んだ後、JacaScript実行(Scripting)へ移行。
レンダリングエンジンは、JavaScriptのコードをJavaScriptエンジンに引き渡して実行させる。
JavaScript実行の流れ
(JavaScriptコード)
↓
字句解析
↓
(トークン列)
↓
↓
(抽象構文木)
↓
↓
(実行可能コード)
↓
実行
※JavaScriptエンジンの実装によって異なる。
JavaScriptの実行は、最初にJavaScriptファイルを読み込んだとき以外にも、DOMイベントが発火し、イベントリスナが起動するときに起こる。
5.1 字句解析と構文解析
JavaScriptエンジンは、与えられたコードを何らかの実行可能な形式に変換(コンパイル)した上でJavaScriptに書かれた処理を実行する。
コンパイルを行うために、JavaScriptのコードを抽象構文木(英: abstract syntax tree、AST)と呼ばれるコンパイル可能な形に変換する。 JavaScriptの場合はJavaScriptオブジェクト(JSON)として表現される。
抽象構文木
構文構造をデータ構造に起こしたもの。JavaScriptの文法に沿った形で表現される木構造のデータ。
抽象構文木
{ "range": [ 0, 10 ], "type": "Program", "body": [ { "range": [ 0, 10 ], "type": "VariableDeclaration", "declarations": [ { "range": [ 4, 9 ], "type": "VariableDeclarator", "id": { "range": [ 4, 5 ], "type": "Identifier", "name": "a" }, "init": { "range": [ 8, 9 ], "type": "Literal", "value": 1, "raw": "1" } } ], "kind": "var" } ], "sourceType": "module" }
5.2 コンパイル
JavaScriptエンジン内部のコンパイラは、先ほど構築した抽象構文木を実行可能な形式にコンパイルする。
スクリプト言語の言語処理系の実装の方法
JavaScriptエンジンで多いのは、JIT(Just In Time)コンパイル型の実装
5.3 実行
実行可能な形式にコンパイルされたJavaScriptのコードは、処理系内部の仮想マシン、もしくはCPUで実行される。
6. レイアウトツリー構築 - Rendering
JavaScriptの実行が終わると、レイアウトツリー構築(Rendering)が行われる。
具体的に以下
- スタイルの計算
- レイアウト
レイアウトツリー
ブラウザで DOM と CSSOM を組み合わせて、ページ上の表示可能なすべての DOM コンテンツと、各ノードのすべての CSSOM スタイル情報を取り込んだもの
6.1 スタイルの計算
DOMツリー内の全てのDOM要素に対して、どのようなCSSプロパティが当たるのか計算する。
CSSルールのマッチング処理
CSSOMツリーからCSSルールセットを走査、DOMツリーからDOM要素を走査。 どんなCSSルールが適用されるのかを計算する。
CSS セレクタのマッチング
body > .container > .button { ... }
- DOM要素のclass属性にbutton
- 親要素のclass属性にcontainer
- 親要素のDOM要素名がbody
レンダリングエンジンはセレクタを右から左に解釈してマッチング処理を行う
どのDOM要素に対してどのCSSルールセットが適合するかレンダリングエンジンには分かるようになる。
CSSルールセット
div.my-button, button { background-color: green; color: white; }
の{}
部分
適用されるCSSプロパティの算出
DOM要素にどのCSSプロパティと値が適用されるのか算出する。
(margin, padding,positionの算出ではない)
詳細度の計算など
<p class="foo"> foo </p> .foo { color: red; } p { color: blue; }
.fooのスタイルが当たることの計算
6.2 レイアウト
DOM要素に当たるCSSプロパティを算出した後、レンダリングエンジンはDOMツリー内のすべてのノードの視覚的なレイアウト情報の計算、レイアウトを行う。
設計図的なもの
レイアウト情報
- 要素の大きさ
- 要素のmargin
- 要素のpadding
- 要素の位置
7. レンダリング結果の描画 -Painting
DOMツリーのレイアウト情報の算出が終わると、レンダリング結果の描画(Painting)。
レンダリングエンジンはユーザーが見ることができる実際のピクセルを描画。
3つの処理が行われている。
- ペイント(Paint)
- ラスタライズ(Rasterize)
- レイヤーの合成(Composite Layers)
最後のレイヤーの合成が終わることで、ユーザーの目にはレンダリングエンジンが描画した表示になる。
7.1 ペイント
内部の低レベルな2Dグラフィックエンジン向けの命令を生成。
- RenderTreeを元にDisplay Listと呼ばれる内部の低レベルグラフィックエンジンのための命令の列を生成。
組み込まれるグラフィックエンジンはブラウザの実装ごとに異なる
7.2 ラスタライズ
- 生成された命令を用いて実際にピクセルに描画する。
- レイヤーごとに一枚一枚描画される。
- レイヤーが生成されるのは、
position
やtransform
,opacity
などのプロパティが適用されているとき
レイヤー単位でピクセルに描画するのはなぜ? 再レンダリングする場合、すでに描画が終わったレイヤーを再利用することで、素早く再レンダリングできる場合がある。
7.3 レイヤーの合成
ピクセルにしたレイヤーを合成して最終的なレンダリング結果を生成する。
CPU
コンピューター全体の計算処理
3Dグラフィックなどの画像描写に必要な計算処理
7.4 コンテンツの表示
レイヤーの合成の処理を終えてやっと
レンダリングエンジンがコンテンツを表示します!
8 再レンダリング
ユーザーやブラウザの何らかのアクションやJavaScriptのコードの実行やドキュメント内のイベントによってレンダリングは再度引き起こされる。
再レンダリングが引き起こされるのは?
- DOMイベントが発火するとき
「ブラウザを立ち上げてアドレスバーにURLを打ち込んでEnter押してからページが表示されるまでに (裏側で) 何が起こっているかわかる限り説明してみてください。」
はじめは、この質問を何も見ずに15分考えると、ぼんやりとした流れを説明することしかできなかったのですが、ブラウザの仕組みを勉強したあとは3倍くらいの量できちんと説明できるようになりました◎
参考
- https://ja.wikipedia.org/wiki/HTML%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3
- https://webukatu.com/wordpress/blog/928
- https://qiita.com/Tsuyoshi84/items/5575aff0408ea7e64e68
- https://kotobank.jp/word/%E5%AD%97%E5%8F%A5%E8%A7%A3%E6%9E%90-4120
- https://kotobank.jp/word/%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3-6633
- https://codingjp.com/web/6407/
- レンダリング ツリーの構築、レイアウト、ペイント | Web | Google Developers
- 作者:久保田 光則
- 発売日: 2017/05/26
- メディア: 単行本(ソフトカバー)