ブラウザでページが表示されるまでの流れ

## はじめに
このページはフロントエンドエンジニア歴3年目の著者が改めてブラウザの仕組みを理解するための以下のページを読んで学んだことをまとめた記事です、

https://developer.mozilla.org/ja/docs/Web/Performance/How_browsers_work

## 大まかな流れ
ブラウザでページが表示されるまでの流れは大まかに以下の通り
1. ユーザの何かしらの行動でHTTPリクエストが送られる
1. レスポンスでファイルが届く
1. ブラウザにページが表示される
    1. DOMツリーが構築される
    1. CSSOMが構築される
    1. レンダーツリーが
    1. レイアウト
    1. 描画される
## HTTPリクエスト
### ユーザ操作
ブラウザでユーザが以下のような操作を行うことで、HTTPリクエストが送られる
- アドレスバーでURLを入力
- リンクをクリック
- フォームを送信

### DNS検索
ブラウザが一度も訪れたことのないURLへのアクセスの場合、DNS検索が必要になる。
ブラウザがDNS検索を行うとリクエストはネームサーバによって処理され、ネームサーバがIPアドレスを返す。

### TCPハンドシェイク
IPアドレスが判明するとブラウザはサーバとのコネクションを確立するためにTCP3ウェイハンドシェイクを行う。
#### TCP3ウェイハンドシェイク
以下の3回のやり取りを通して確立する
1. クライアントからサーバへ「接続を開始していいか？」
1. サーバからクライアントへ「いいよ！こっちからも接続を開始していい？」
1. クライアントからサーバへ「いいよ！」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982124/1e4f4b73-d0a7-096e-1fdc-dbc7eeed34ce.png)
（引用元：https://www.infraexpert.com/study/tcpip9.html）

この3回のやり取りをすることでクライアントとサーバの接続が確立される。

### TLSネゴシエーション
HTTPSの場合はもう一つのハンドシェイクが必要になる。このハンドシェイクはTLSネゴシエーションと呼ばれる。
通信の暗号化に使用する暗号の種類を決定し、サーバを認証し、実際のデータ送信が始まる前に安全な通信の準備を整える。コンテンツのリクエストを実際に送信する前に、さらに5回のラウンドトリップを必要とする。
1. クライアントからサーバへ「SSLの通信を開始するよ！情報を送るよ！」
1. サーバからクライアントへ「もらった情報をもとに使用する暗号化とハッシュ関数のアルゴリズムを決めたよ！情報を送るよ！」
1. クライアントからサーバへ「秘密の乱数情報（=プリマスタシークレット）を生成したよ！情報を送るよ！」
1. 乱数とプリマスタシークレットを使用して生成される「マスターシークレット」から共通鍵を生成。以降は共通鍵を使用して暗号化通信を行うことを通知。クライアントがサーバ認証に成功して共通鍵を共有できたことをサーバに通知。
1. サーバ側でも受信したプライマスタシークレットと乱数をもとにしてマスターシークレットを生成し、共通鍵を生成。クライアントに共通鍵を生成できることをクライアントに通知。サーバがクライアント認証に成功して、共通鍵を共有できたことをクライアントに通知。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982124/41fe1278-b576-4fc6-e5f7-08a767bc432e.png)
（引用元：https://www.infraexpert.com/study/security28.html）

## HTTPレスポンス
ウェブサーバへのコネクションが確立されると、ブラウザが最初のHTTPリクエスト（GETメソッド）を送信する。リクエストを受け取ったサーバはレスポンスヘッダーとHTMLのコンテンツを返す。

## クリティカルレンダリングパス
Webサイトのリソース (HTML、CSS、スクリプト) のダウンロード、処理、ページの一番最初のピクセルのレンダリングまでの一連の流れを、クリティカルレンダリングパスと呼びます。
（参考：https://perfdata.jp/blog/blog-2017-09-15.html）
クリティカルレンダリングパスの5つのステップは以下の通り。
1. DOMツリーの構築
1. CSSOMの構築
1. レンダーツリー
1. レイアウト
1. 描画

### DOMツリーの構築
クリティカルレンダリングパスの1つめのステップではHTMLのマークアップを処理し、DOMツリーを構築する。HTMLの構文解析は、トークン化とツリーの構築に分かれる。パーサーはトークン化された入力情報を文書ツリーを構成する文書に変換する。

DOMツリーは文書のコンテンツを表す。`<html>`要素は最初の要素であり、文書ツリーのルートノードになる。

`async`/`defer`属性がない`<script>`要素はレンダリングをブロックし、HTML構文解析を停止させてしまう。

#### 事前読み込みスキャナー
ブラウザがDOMツリーを構築する間に事前読み込みスキャナーが処理可能なコンテンツを解釈し、CSSやJavascript、ウェブフォントなどの優先度の高いリソースのリクエストを行う。

事前読み込みスキャナーのダウンロードを遅らせないためには、`script`タグに`async`属性を付与するか、スクリプトの解釈と実行順が重要である場合には`defer`属性を付与する。

CSSの取得はHTMLの構文解析やダウンロードを遅延させないが、JavsScriptの実行を遅延させる。理由はJSがCSSプロパティの要素への影響を問い合わせるために使われるため。

### CSSOMの構築
クリティカルレンダリングパスの2つめのステップはCSSを処理してCSSOMツリーを構築することである。
ブラウザはCSSのルールをブラウザが理解できるスタイルのマップに変換する。ブラウザはCSSのルールセットを読み取り、CSSセレクタに基づいて、親、子、兄弟の関係から構築されるノードのツリーを生成する。

ブラウザはノードに対して適用される最も一般的なルールからスタートして、より特定されたルールを再起的に適用し、最終的なスタイルを計算する。

#### その他の処理
##### JavaScriptのコンパイル
CSSOMが生成される間、JavaScriptファイルを含む他のアセットが事前読み込みスキャナーによってダウンロードされる。JavaScriptは構文解析され、コンパイルされて解釈される。

##### アクセシビリティツリーの構築
ブラウザはコンテンツを理解し翻訳する補助機器で使用されるアクセシビリティツリーも構築する。アクセシビリティオブジェクトモデル（AOM）は補助機器向けのDOMのようなものである。

AOMが構築されるまで、スクリーンリーダーでコンテンツにアクセスすることはできない。

### レンダーツリーの構築
クリティカルレンダリングパスの3つめのステップはDOMとCSSOMをレンダーツリーの形式へと組み合わせることである。レンダーツリーの構築はDOMツリーのルートからスタートし、目に見えるノードを走査する。

:::note info
スタイル、レイアウト、描画、合成のステップをレンダリングと呼ぶ
:::

<details><summary>走査とは</summary>

画面を画素に逐次分解すること。また、逐次分解された画素を画面に組み立てること
引用：https://kotobank.jp/word/%E8%B5%B0%E6%9F%BB-5316

英語版では「traverse」という単語が使われている
1. 〔山などを〕越える
1. 〔場所を〕横切る、横断する
1. 〔～に〕矛盾する、反対する、抗弁する、否認する
1. 〔～を〕詳しく検討する
引用：https://eow.alc.co.jp/search?q=traverse
</details>

レンダーツリーに含まれないものは以下の通り
- `<head>`要素のゆおな表示されることがない要素
    - その子要素
- `dinsplay: none;`を指定されたすべてのノード

レンダーツリーに含まれるものは以下の通り
- `visibility: hidden;`が適用されたノード

目に見えるノードにはCSSOMのルールが適用される。レンダーツリーはコンテンツと計算されたスタイルを持つすべての目に見えるノードを保持する。すべての関連するスタイルとDOM上の目に見えるノードをマッチングし、CSSカスケードに基づいてそれぞれのノードに対応する計算されたスタイルを決定する。

### レイアウト
クリティカルレンダリングパスの4つめのステップは各ノードの平面上の位置を計算するためにレイアウト処理を実行することだ。
- レイアウト
    - レンダーツリーに含まれるすべてのノードの寸法と位置を決める処理
    - ページ上のそれぞれのオブジェクトの寸法と位置を決定する
    - レンダーツリーが構築されるとすぐにレイアウトが始まる
        - ビューポートの寸法を基本として、一般的にbodyからスタートし、すべてのdobyの子孫をそれぞれの要素のボックスモデルプロパティに合わせてレイアウトする
        - 画像のように寸法がわからない代替要素のためのプレースホルダースペースを作成する
- 再フロー
    - 文書全体、あるいはページの一部分の寸法と位置を決める処理
        - 画像の寸法がわかるとすぐに再フローが発生する

### 描画
クリティカルレンダリングパスの最後のステップは、個別のノードを画面に描画することだ。描画段階でブラウザはレイアウト段階で計算されたそれぞれのボックスを画面上の実際のピクセルに変換する。描画は、テキスト、色、強化、シャドウ、ボタンや画像のような置換要素を含む、要素の全ての視覚的な部分を画面に描くことを含む。

スムーズなスクロールとアニメーションを実現するために、スタイルの計算や再フロー、描画などメインスレッドを占有するすべての処理は、16.67ms未満で環境する必要がある。2回目以降の描画を最初の描画より高速にするため、一般的には画面への描画を複数のレイヤーに分解する。この場合合成が必要になる。

#### 合成
文書のセクションが異なるレイヤーに描画されていて、それらが重なり合っている時、コンテンツを画面上に正しい順番で描画するために合成が必要になる。

## 操作可能性
読み込み処理が、遅延された`onload`イベントの発行により実行されるJavaScriptを含む場合、メインスレッドがビジー状態隣スクロールやタッチ、その他の操作ができない場合がある。