Posted on: Written by: K-Sato

Table of Contents

仕組みを知る

ブラウザ内のコンポーネント

  • レンダリングエンジン: HTMLの描写エンジン
  • JavaScript エンジン : JavaScript の実行環境を提供するソフト ウェアコンポーネント

image

ブラウザレンダリングの流れ

(1) Loading(2) Scripting(3) Rendering(4) Painting

image

①Loading(リソース読み込み)

Loadingで行われる事。

(1) リソースのダウンロード(Download)
サーバからリソースの取得

(2) リソースのパース(Parse)
取得したリソースを公文解析してレンダリングエンジンの内部表現に変換する。

HTTPレスポンスとして返されるHTMLは下記の工程でDOMツリーへと変換される。

1. 字句解析によるトークンのリスト化
2. 構文解析による構文木の構築
3. 構文木内にある JavaScript を実行しつつ DOM ツリーの構築

②Scripting(Javascript実行)

JSのコードをJSエンジンに引き渡して実行させる。

一般的な流れは下記

JSコード
↓
字句解析
↓
構文解析
↓
コンパイル
↓
実行
処理系内部の仮想マシン、もしくはCPUで実行される

③Rendering(レイアウトツリー構築)

スタイルの計算(Calculate Style)とレイアウト(Layout)が行われる。

  • スタイルの計算: DOMツリーの中内の全てのDOM要素に対してどのようなCSSプロパティが当たるかを計算(すべての DOM 要素に対して、CSS ルールの CSS セレクタがマッチするかを総当りで試行する。)
  • レイアウト(Layout): DOM ツリー内のすべてのノードの視覚的なレイアウ ト情報の計算、レイアウト( Layout)を行う

image

④Painting(レンダリング結果の描画 )

このフェーズでようやくレンダリングエンジンは ユーザーが見ることができる実際のピクセルを描画する。

このフェーズでは下記を行う。

  • ペイント(Paint): RednerTreeを元にDisplay Listと呼ばれる内部の低レベルグラフィック エンジンのための命令の列を生成
  • ラスタライズ(Rasterize): 生成された命令を用いて実際にピクセル(ビットマップ )へと 描画
  • レイヤーの合成(Composite Layers) : ピクセルにしたレイヤーを合成して最終 的なレンダリング結果を生成

チューニングの基礎

チューニングのトレードオフ

  • 開発者の時間的リソース
  • コードの単純さ(可読性、保守性、拡張性)

推測するな、計測せよ

効果的なチューニングのためには、まずは計測し、どうすることが最も効果的 なのか検討していく必要がある。

ボトルネックを探し出す

ある一連の処理の中で最も多くの時間を消費し ている箇所をボトルネックと呼ぶ。

チューニングのトレードオフによる無駄なペナルティを避けるためには、ボト ルネックを特定することは必要不可欠。

目指すべき指標を設定する

RAILというパフォーマンス指標が存在する

  • Response(応答): ユーザーの何らかのアクションに対してウェブページがユーザー インターフェイス上の変化を引き起こして、応答するまでの時間
  • Animation(アニメーション): アニメーション中に連続して行われるフレームの中で 1 フレー ムの処理の時間
  • Idle(アイドル処理): アイドル状態に実行される JavaScript の処理時間
  • Load(読み込み): ウェブページのコンテンツの読み込みにかかる時間

下記がそれぞれの目安の基準時間

image

計測する手段

  • Chrome DevTools などデベロッパーツールによる計測
  • JavaScript による計測
  • パフォーマンス診断ツールの利用
  • パフォーマンスの継続的監視

リソース読み込みのチューニング

読み込むリソースの大きさと数を減らす

リソースの最小化

 HTML,CSS,JS等のファイルは改行・タブ等の不要なバイトを含むので、それぞれリソース最小化ツールを使用する事でリソースサイズを小さくできる。

適切な画像形式を選択する

画像ファイルはその形式ごとに適した用途があります。それぞれの用途に最適 な画像を用いることでファイルサイズを削減できる可能性がある。

image

リソースを事前に読み込みしておく

DNS プリフェッチ

link 要素の rel 属性に dns-prefetch を指定すると、href 属性に指 定したドメインの名前解決をバックグラウンドで処理してくれる。

名前解決さ れたドメインの IP アドレスはブラウザのキャッシュに格納される。

リソースのプリフェッチ

link 要素の rel 属性に prefetch を指定すると、リソースの事前読み込みを行 うことが可能。

事前読み込みされたリソースはブラウザのキャッシュ内に格納される。

コネクションの接続

rel 属性に preconnect を指定すると、指定したドメインへの接続のみをあら かじめ行

プリレンダリング

rel 属性に prerender を指定すると、ウェブページのレンダリングをバックグ ラウンドで行わせることができる。

Gzip圧縮を活用する

HTTP/1.1ではHTTPレスポンスのコンテンツを圧縮して配信可能。

コンテンツを圧縮する事でサイズを大きく減らすことができる。

CDNを用いてリソースを配信する

CDN(Content Delivery Network)を利用することで、リソースの配信を最適化することが可能。

CDN とは、ウェブのリソースを配信することに最適化されたネットワークの ことを指す。
ウェブサイトのリソースをキャッシュし、世界中に置かれているCDNの配信サーバーにキャッシュし、
そのサーバーがかわりにそのコンテンツを配信することで、
1つのサーバーで配信するよりも負荷が分散され、かつ高速なリソース配信を行うことができるという仕組み

有名なCDNにCloudflare, Amazon CloudFront, Fastlyなどがある。

リダイレクトをしない

ウェブサイト内の不要なリダイレクトは避けるべき。 リダイレクトは HTTP リクエストを余分にやりとりする必要がある。

また、違うドメインへのリダイレクトは、Keep-Alive も有効にならないので、余計 な DNS の名前解決や TCP3 ウェイハンドシェイクなどの接続の前処理を再び行 う必要がる。

ブラウザのキャッシュを活用する

ブラウザのキャッシュを活用することで、HTTP リクエストの数を減らしたり、HTTP レスポンスのサイズをとても小さくしたりすることが可能。

Expiresヘッダー(強いキャッシュ)

HTTP では、HTTP レスポンスヘッダーに Expires ヘッダーを設定すること で、リソースのキャッシュをブラウザ側に指示可能。

キャッシュされたファイルが消えるか、期限 が切れるまでは、ブラウザが動作しているマシンの内部にキャッシュされ続ける 強いキャッシュ。

Cache-Controlヘッダーの設定(強いキャッシュ)

Expires ヘッダーと同じ強いキャッシュを有効にできます。Cache-Control によってキャッシュを一度 有効にすることでブラウザにキャッシュが存在する場合にはそのリソースへの HTTP リクエストは送信されないようにる。

ブラウザは、Cache-Control ヘッダーと Expires ヘッダー両方が設定されてい る場合には Cache-Control ヘッダーを優先する。

Last-Modifiedヘッダーの設定(弱いキャッシュ)

Last-Modified ヘッダーには、その URL のリソースが最後に変更されたのが、 いつなのかを設定する。

クライアントが送信する HTTP リクエスト内に含まれている条件に合致すれば、 HTTPサーバーは304 Not Modifiedレスポンスを返すことで不要なデータの送 信を抑えることが可能。

キャッシュしつつ、変更が発生した場合に は即時キャッシュをクリアしたい場合に利用される。

ETagヘッダーの設定(弱いキャッシュ)

ブラウザがあるリソースに対して初めてアクセスするとき、HTTP サーバー はレスポンスヘッダーの中に次のような Etag ヘッダーを返送。

Etag: "E8sKOBq0HCGxD2KPqSX2EyVC2q7Rmd"

ブラウザは取得したファイルと ETag の対を保存しておく。ブラウザは HTTP リク エストヘッダーの中に次のような If-None-Match ヘッダーを送信します。ここで 指定しているのは先程の Etag の値です。

If-None-Match: "E8sKOBq0HCGxD2KPqSX2EyVC2q7Rmd"

HTTP サーバーは、HTTP クライアントからこの If-None-Match ヘッダー を受け取ると、リソースの現在の ETag の値と比較します。これらが同じであ れば、リソースは変わっていないことになるので、HTTPサーバーは304 Not Modified という、リソースを含まないレスポンスヘッダーだけの HTTP レスポ ンスを返す。

Service Workerの利用

Service Workerを使えば、JavaScript からキャッシュの制御を柔軟に行うことが可能。

一度 Service Worker が登録されると、ブラウザがリ ソースを取得する際には Service Worker 内に記述されているロジックを参照して キャッシュからリソースを取得するかウェブサーバーからリソースを取得するかを決める。

Service Worker は、ウェブページとウェブサーバーの間にあるプロクシのよう な形で動作する。

image

About the author

I am a web-developer based somewhere on earth. I primarily code in TypeScript, Go and Ruby at work. React, RoR and Gin are my go-to Frameworks.