WEBフロントエンドハイパフォーマンスチューニング
ブラウザレンダリングの仕組み
- レンダリングの流れはレンダリングエンジンの実装に依存していて異なる
- プロプライエタリ(構造・技術を独占的に保持し情報を公開していない)
- Blink は 2013年に WebKit から分岐している
レンダリングエンジン
- HTML の描画エンジン
- 画像, CSS, JS などの各種リソースを読み取って画面上のピクセルとして描画する
- メーラーの中にもレンダリングエンジンが搭載されていてHTMLメールを描画する
- Blink(Chrome), Gecko(Firefox), WebKit(Safari) など
JavaScriptエンジン
- JavaScriptの実行環境を提供する
- V8(Chrome), SpiderMonkey(Firefox), JavaScriptCore(Safari) など
- WebView も OS でそれぞれエンジンが違う
レンダリングの流れ
Loading
- リソースのダウンロード(Download)
- HTML, CSS, JavaScript, 画像
- リソースのパース(Parse)
- 構文解析してレンダリングエンジンの内部表現に変換
- HTML → DOM ツリー, CSS → CSSOM ツリー に変換
- リソースの取得
- URLに含まれるホスト名の名前解決
- TCP接続の確立
- TLS接続の確立
- HTTPリクエストの送信とレスポンスの受け取り
- IP
- パケット (IPヘッダー + データ)
- IPヘッダー
- パケットの長さ、送信元IPアドレス、宛先IPアドレス、誤り検出チェックサムなど
- 20〜24バイト
- TCP
- 相手に確実に届いているかどうかを確認する
- データの欠損や破損を検知して再送する
- データの送信順を保証する
- TCPコネクション
- IPアドレスとポートを指定して接続を確立する
- 3ウェイハンドシェイク
- クライアント → SYNパケット → サーバー
- クライアント ← SYN-ACKパケット ← サーバー
- クライアント → ACKパケット → サーバー で接続確立
- TLS
- クライアントとサーバーの認証機能
- 通信データの暗号化
- 通信データの改ざんの検出
- 3往復あるので片道分の時間×6の時間かかる
- +サーバーの証明書チェーンの検証
- UDP
- 1方向の送信なのでTCPに比べて早いが、データの欠損検知や送信順保証はない
- DNSはUDPを利用できる(TCPも使うこともある)
- QUICプロトコルはUDP上に構築
- HTTP
- TCP上
- KeepAliveを利用するとTCP接続を破棄せずにその中で何度もやりとりできる
- DNS
- プロトコルの名称
- クライアント内のDNSリゾルバ(スタブリゾルバ)を通じて通信を行う
- リソースの読み込み
- HTMLはDOMツリーに
- CSSはCSSOMツリーに
Scripting(JavaScriptの実行)
- レンダリングエンジンはJSコードをJavaScriptエンジンに引き渡して実行させる
- 字句解析
- コードを解析して分割、トークン列にする
- 構文解析
- トークン列を抽象構文木(AST)に変換する
- コンパイル
- 抽象構文木を実行可能な形式にコンパイル
- V8,Nitro(Safari)はJITコンパイル型
- 実行
- 仮想マシンもしくはCPUで実行される
Rendering
- レイアウトツリーの構築
- スタイルの計算
- DOMツリー内の全てのDOM要素に対してどのようなCSSが当たるのかを計算する
- CSSOMツリー内を全て参照してCSSルールのCSSセレクタのマッチング処理
- DOMツリーからすべてのDOM要素に対してCSSルールセットが当たるかを総当たりで計算している
- セレクタを右から左に解釈している
- CSSルールセットを詳細度でソートして計算
- 詳細度は3つのレベル
- a: IDセレクタの数
- b: クラスセレクタ、属性セレクタ、擬似セレクタの数
- c: 要素セレクタ、擬似要素セレクタの数
- 全称セレクタは無視
- style属性、!important は最優先
Layout
- 視覚的なレイアウト情報の計算
- 要素の大きさ、マージン、パディング、位置、z軸の位置
- LayoutTree
Painting
- レンダリング結果の描画
- ピクセルを描画
- ペイント
- 2Dグラフィックエンジン向けの命令を生成
- ラスタライズ
- 生成された命令を用いてピクセル(ビットマップ)へと描画
- レイヤー(z軸の上下関係を持っている)生成する
- position: absolute
- position: fixed
- transform: translate3d() などGPUで描画・合成
- opacity
- レイヤーの合成
- ピクセルにしたレイヤーを合成する
- CPU/GPU
- 基本的にCPUだが一部のCSSプロパティを使うとGPUを使う
- 再レンダリング
- DOM Eventが起こりレンダリングがとこからかの段階から再実行される
第3章 チューニングの基礎
- トレードオフ
- 時間的リソース
- コードの単純さ(可読性・保守性・拡張性)
- ベストプラクティスは、多くの場合やったほうが良いチューニングテクニック
- 推測するな、計測せよ
- まず計測すること
- ボトルネックをさがしだす
- RAIL指標
Chrome DevTools
Network パネル
- 時間のかかるリソースの特定
- 青い線は DOMContentLoaded、赤い線はLoadイベントが発生した時点
DOMContentLoaded イベントは、最初の HTML 文書の読み込みと解析が完了したとき、スタイルシート、画像、サブフレームの読み込みが完了するのを待たずに発生します。
load イベントは、ページ全体が、スタイルシートや画像などのすべての依存するリソースを含めて読み込まれたときに発生します。これは DOMContentLoaded が、ページの DOM の読み込みが完了すれば、リソースの読み込みが完了するのを待たずに発生するのと対照的です。
https://developer.chrome.com/docs/devtools/network/reference/#timing-explanation
- Connection Setup
- Queue: レンダリングエンジン内のキューイング処理されるのにかかる時間
- Stalled: マシンのネットワークを活性化させるのにかかる時間
- DNS Lookup: ドメイン名をIPアドレスに解決するために行うDNSルックアップにかかる時間
- Initial connection: TCPでの接続を確立するのにかかる時間
- SSL: TLSでの通信トンネルを確立するのにかかる時間
- Request/Response
- Request sent: HTTP リクエストを送信するのにかかる時間
- Waiting(TTFB): Time to First Byte - リクエストを送信し終えてから最初のデータを受け取るまでにかかる時間
- Content Download - コンテンツの最初のバイトからすべて受け取り終えるまでにかかる時間