ブラウザの仕組みとパフォーマンス最適化
はじめに
前回の記事ではインターネットの大まか流れについて勉強しました。
クライアントからリクエストを送ったら、サーバはこのリクエストを処理した結果のレスポンスを返します。このレスポンスではWEBページのHTML、CSS、JavaScriptファイルが含めてます。そのレスポンスをブラウザが解析して画面に表示します。
レスポンスデータの一部を見てみましょう。
このテキストに構成されてるデータをウェブブラウザはどうやって画面に見せるのでしょうか?
ウェブブラウザ
そもそも、ブラウザは何なのでしょうか?いつも通りウィキペディアに検索してみました。
ウェブブラウザ(インターネットブラウザ、web browser)とは、パソコンやスマートフォン等を利用してWebサーバに接続するためのソフトウェアであり、ウェブページを表示したり、ハイパーリンクをたどったりするなどの機能がある。単にブラウザ(ブラウザー)とも呼ばれる。
主なウェブブラウザとして、Google Chrome、Safari、Microsoft Edge、Mozilla Firefox、Opera、Internet Explorer、Vivaldi等がある。Windows 7など古いOSではサポートが終了しているものがある。
ウェブサーバに接続するためのソフトウェアで、HTML文書とファイルを画面に出力してくれることだと思います。
世界でどのようなブラウザがあるのでしょうか?ブラウザの数と占有率を下記のサイトを参考して調査してみました。
2022年から2023年3月間の占有率は下記になります。
- Chrome
- Safari
- Edge
- Opera
- Firefox
私はPCではChromeを利用してMobileではSafariを使ってます。このブラウザについてもうちょっと具体的に勉強したいと思います。
ウェブブラウザの機能
ウェブブラウザの主な機能はクライアントから送ったリクエストをサーバに転送して、送られたレスポンスデータをブラウザ上に表示することです。
上記の例みたいにHTMLもできるし、Image、PDF、XMLなどのファイルも表示することができます。このようなものを表示するためにはURIを利用します。
各ウェブブラウザについて決められた仕様はありませんが、大体似てる機能を提供してます。
- URIを入力できるアドレスバー
- 前と後のページに移動するボタン
- ブックマーク
- 更新、停止ボタン
- ホームボタン
もちろん、各ブラウザの固有の機能もそれぞれあります。
ブラウザの構造
ブラウザの重要な構成要素は下記になります。
- 使用者インターフェース:前/後ページに移動するボタン、アドレスバー、ブックマークなどページビュー以外の部分
- ブラウザエンジン:使用者インターフェースとレンダリングエンジン間の動作をコントロール
- レンダリングエンジン:HTML、CSSをパーシングして画面にリクエストしたページを表示する。
- ネットワーク通信:HTTP通信などのネットワークで利用する。
- UIバックエンド:基本的なWigetを書く
- JavaScriptインタープリター:JavaScriptコードを分析して実行
- データストレージ:LocalStorage、SessionStorage、クッキーなどを保存する
図に表すると下記になります。
レンダリングエンジン
ブラウザで画面に表示することはレンダリングエンジンの役割になります。
各ブラウザが使用してるレンダリングエンジンは違います。
ブラウザ名 | レンダリングエンジン |
---|---|
Chrome | Blink |
Safari | Webkit |
Microsoft Edge | Blink |
Opera | Blink |
Firefox | Gecko |
internet explorer | Trident |
ブラウザごとのレンダリングエンジンが違うため、すべてのブラウザが同じソースコードをそれぞれ解析します。なので、Chromeで動作したコードがSafariでは動作できない場合が発生します。
また、性能の差、機能の支援有無が出てる理由になります。
レンダリングエンジンの動作プロセス
レンダリングエンジンはリクエストによるコンテンツが取得されたらはじめます。このコンテンツの内容は8KB単位で転送されます。
基本的な動作プロセスは下記になります。
その前にDOMとCSSOMについてみてみましょう
DOMとは
DOMはDocument Object Modelです。HTMLやXML文書を表現する方式のモデルです。テキスト、リンク、イメージを表するHTMLタグをブラウザがオブジェクトに変換して階層構造に表現することをDOMツリーだと言います。
CSSOM
CSSOMはCSS Object Modelです。DOMではページのすべてのコンテンツが含まれてます。CSSOMはスタイルに関する情報があります。
DOMと同じようにツリー構造ですが、HTMLに適用されるCSSの規則です。CSSOMはDOMと一緒にページを配置して描くレンダツリーに使用されます。
DOMツリー構築ためにHTMLのパーシング
レスポンスデータになるHTMLをパーシングしてDOMのノードをを作ります。このノードを集めてDOMツリーを作ります。
それとCSSデータをパーシングしてCSSOMツリーを作ります。
ブラウザはレンダリングする文書をHTMLとCSSに分けて読み込みます。レスポンスデータとしてのHTMLとCSSは単純なテキストなので、必要な変換をするためにHTML ParserとCSS Parserを使ってオブジェクトモデルを作ります。
このプロセスが漸進的に行います。レンダリングエンジンはより良いユーザーエクスペリエンスをために、すべてのHTMLのパーシングを待たなくて、配置と描くプロセスをはじめます。
なので、ネットワークから内容が転送されることを待ちながら一部を画面に表示します。
DOMの生成プロセス
- サーバからレスポンスデータをブラウザに転送します。
- HTML文書がネットワークを通じて受信されたら、バイトストリームを利用して指定された文字エンコディングを基板で文字に変換します。
- 変換された文字列を字句解析をしてグループ化してトークンを作ります。ここでは開始タグ、終了タグ、属性名、属性値、テキストなどになります。
- グループしたトークンをパーサーがノードに変換します。
- DOMノードを作ります。
- DOMツリーを構成します。
CSSOM生成プロセス
CSSOMの生成プロセスはDOMと類似です。しかしCSSOMはHTML代わりにCSSから構成されます。
JavaScriptレンダリングプロセス
JavaScriptはレンダリングエンジンではなくJavaScriptエンジンが処理します。HTML Parserは<script>
を読んだら、JavaScriptコードを実行するためDOMの生成プロセスを停止してJavaScriptエンジンに制御権を渡します。
制御権を渡してもらったJavaScriptエンジンは<script>
内部のJavaScriptコードまたは<script>
に作成されてるsrc
属性に定義されたJavaScriptファイルをロードしてパーシンして実行します。
実行が終わったら、HTML Parserに制御権を渡してブラウザがDOMの生成を再開します。
このように、ブラウザは同期的にHTML、CSS、JavaScriptを処理します。なので、<script>
タグの位置による処理の順番が変わるので、スクリプトの順番は重要です。
レンダツリー構築
HTMLから作れらたDOM、CSSから作られたCSSOMを構成されたら、レンダツリーを構築することができます。このツリーはDOMとCSSOMの組み合わせです。
しかし、このレンダツリーではすべてのノードを表示することではなく、ページに表示されるノードだけ含まれます。例えばCSSの属性がdisplay: none;
に指定された要素はレンダツリーに含まれません。この属性がページのレイアウトに表示しない属性だからです。
同じように、<head>
、<script>
、<meata>
、などページに表示されないHTMLタグもこの時に表示しないようになります。なので、この要素はレンダツリーの一部になりません。
レンダツリー配置
レンダツリーが構築されたら、ブラウザはページにどのような要素が必要かと各要素にどのようなスタイルが適用されるかを分かるようになります。
しかし、各要素がどこに配置されるか、サイズはどれぐらいかをまだ分からない状態です。なので、レンダツリー配置でブラウザは画面に表示される位置と空間を計算します。
このレンダツリー配置をレイアウトまたはリフローと言われます。
レンダツリー描く
レンダツリーの配置が終わったら、実際に画面を描くことです!
ペイントと言われるレンダツリー描くは各ノードを画面に書きます。一部の要素は他の要素と重ねてしまう場合があるので、順番が重要です。
大体の場合はDOMに表示される順番ですが、特定なCSSの属性が順番に影響がある場合もあります。
具体的にはbackgroundとborderが先に描かれて、その子の要素を描いてテキストイメージが描かれます。しかし、z-index、opacityなのを利用して順番を変更することもできます。
レンダツリー描くプロセスはJavaScriptがHTMLやCSSを修正した際にまた発生します。なので、コードを作成する時にこの段階が効率的に実行できるように考えないといけないです。
ReflowとRepaint
レンダツリーを描いたら、最終的にブラウザにページが表示されます。しかし、HTML要素や大きさの修正、レイアウトが変わったら、Reflowが発生します。このプロセスはレンダツリーで表示される各要素を改めて計算しないといけないため性能的に費用が掛かる部分です。なので、なるべくReflowが発生しないように構築する方が良いです。
Reflowが発生する場合は次になります。
- DOMに要素を追加、削除、アップデート、移動される場合
- width、height、font-size、margin、borderなどレイアウトに影響があるCSSのスタイル変更
- :hoverなどの擬似クラス活性化
- テキストのノード内容変更
- Windowの大きさ変更、スクロール
なので、DOMにノードの追加、削除、位置変更、大きさ変更とCSSによる変更(アニメーションなど)、フォント変更、テキスト内容変更、イメージ大きさ変更、WindowsのResizingなど画面の構造について変更があったらReflowが発生すると思います。
Repaint
画面の構造が変更された場合はReflowプロセスを通じて構造を改めて計算してRepaintをして画面を新しく描きます。なので、画面お構造が変更されたらReflowとReapint両方発生します。
でも、画面の構造が変更されない場合は画面おRepaintのみ発生します。例えば、color、background-color、visibility、など視覚的なスタイルでは影響があるが、レイアウトでは影響がない場合です。
WEB性能最適化
ブラウザの複雑な動作原理を理解することで、 WEBページを性能を最適化するためのツールも利用できます。
このツールはGoogle Chromeようなブラウザで提供する開発者ツールを使うことです。
Chromeの開発者ツール
Chromeの開発者ツールではWEBアプリケーション内部を確認してリアルタイムで性能を分析できるツールです。
HTML、CSS、JavaScriptがどのように解析され、実行されてるかについて情報を提供してくれます。
Performance
Chromeの開発者ツールのPerformanceタブを使用することで、アプリケーションの実行中に発生する全ての活動を見ることができます。JavaScriptの解析と実行、レイアウト、レンダリング、ページロードの性能の側面を確認できます。
Timingsの項目ではFP
、FCP
、DLC
、LCP
、L
という部分があります。
- FP : First Paintでページナビゲーション後、最初のピクセルを描いた瞬間です。
- FCP : First Contentful Paintで最初の要素(テキストや画像)を初めて描いた瞬間です。
- DCL : Dom Content LoadedでDOM Treeを構成してスクリプト(+deferスクリプト)を実行完了した時の時間です。
- deferスクリプトがない場合、FPより先にDCLが来ることもあります。
- LCP : Largest Contentful Paintで一番大きいエレメントを描いた瞬間です。
- L : Loadでドキュメントのリソースを全てロードした時です。
Network
ネットワークタブはページをロードする時に発生する全てのネットワークやり取りについて詳細な内容を表示します。この時にロードの速度が遅いリソースを分析して性能向上ために最適化できます。
Lighthouse
LighuthouseはWEBページの品質を改善するため自動化されたオープンソースツールです。
性能、アクセシビリティ、プログレッシブWEBアプリ、SEOなどの監視機能を提供してくれます。
Zennのメインページ結果ですが、100点でした!素晴らしいですね!!👏🏻
まとめ
HTML、CSSをパーシングしてDOMとCSSOMを生成する初期段階から、レンダリングツリーを構成しレイアウトとペイントの段階まで、WEBサイトがクライアントの画面に表示されるようにする複雑なプロセスでした。
また、性能改善するために、Chromeの開発者ツールを利用してLighthouseみたいなツールで性能改善できる部分も見てみました。
今までの説明が皆さんにも分かりやすく説明できていればと嬉しいです。
Discussion
素晴らしいです。
Bookmarkしましたw w
優秀なエンジニアさん笑
ありがとうございます