ブラウザレンダリング¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. ブラウザレンダリングの仕組み¶
構成する処理¶
以下の8つの処理からなる。
クライアントの操作のたびにイベントが発火し、Scriptingプロセスが繰り返し実行される。
- Downloading
- Parse
- Scripting
- Rendering
- CalculateStyle
- Paint
- Rasterize
- Composite
01-02. マークアップ言語¶
▼ マークアップ言語とは¶
ハードウェアが読み込むファイルには、バイナリファイルとテキストファイルがある。
このうち、テキストファイルをタグとデータによって構造的に表現し、ハードウェアが読み込める状態する言語のこと。
▼ マークアップ言語の歴史¶
Webページをテキストによって構成するための言語をマークアップ言語という。
1970年、IBMが、タグによって、テキスト文章に構造や意味を持たせるGML言語を発表した。
xml
形式:Extensible Markup Language¶
▼ xml
形式とは¶
テキストファイルのうち、何らかのデータの構造を表すことに特化している。
▼ スキーマ言語とは¶
マークアップ言語の特にxml
形式で、タグの付け方は自由である。
しかし、利用者間で共通のルールを設けた方が良い。
ルールを定義するための言語をスキーマ言語という。
スキーマ言語に、DTD:Document Type Definition (文書型定義) がある。
*実装例*
<!DOCTYPE Employee[
<!ELEMENT Name (First, Last)>
<!ELEMENT First (#PCDATA)>
<!ELEMENT Last (#PCDATA)>
<!ELEMENT Email (#PCDATA)>
<!ELEMENT Organization (Name, Address, Country)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Address (#PCDATA)>
<!ELEMENT Country (#PCDATA)>
]>
html
形式:HyperText Markup Language¶
▼ html
形式とは¶
テキストファイルのうち、Webページの構造を表すことに特化している。
01-03. JavaScript¶
マークアップ言語へのJavaScriptの組み込み¶
▼ インラインスクリプト¶
js
ファイルを直接的に組み込む。
<script>
document.write("JavaScriptを直接的に組み込んでいます。");
</script>
▼ 外部スクリプト¶
外部js
ファイルを組み込む。
<script src="sample.js"></script>
CDN (グローバルなキャッシュサーバー) の仕組みを使用して、Web上からWebページを取得もできる。
<script
src="https://cdn.jsdelivr.net/npm/lazyload@2.0.0-rc.2/lazyload.min.js"
integrity="sha256-WzuqEKxV9O7ODH5mbq3dUYcrjOknNnFia8zOyPhurXg="
crossorigin="anonymous"
></script>
▼ scriptタグが複数ある場合¶
1
個のWebページのhtml
ファイル内で、scriptタグが複数に分散していても、Scriptingプロセスでは、1つにまとめて実行される。
そのため、より上部のscriptタグの処理は、より下部のscriptに引き継がれる。
1。
例えば、以下のコードがある。
localNum
<p>見出し1</p>
<script>
var globalNum = 10;
</script>
<p>見出し2</p>
<script>
globalNum = globalNum * 10;
</script>
<p>見出し3</p>
<script>
document.write("<p>結果は" + globalNum + "です</p>");
var foo = true;
</script>
<script src="sample.js"></script>
// sample.js
// 無名関数の即時実行。定義と呼び出しを同時に実行する。
(function () {
// 外側の変数 (foo) を参照できる。
if (foo) {
console.log("外部ファイルを読み出しました");
}
var localNum = 20;
function localMethod() {
// 外側の変数 (localNum) を参照できる。
console.log("localNum");
}
// 定義したメソッドを実行
localMethod();
})();
- 実行時には以下の様に、まとめて実行される。
ここでは、html
ファイルで定義した関数の外にある変数は、グローバル変数になっている。
1
個のページを構成するhtml
ファイルを別ファイルとして分割していても、同じである。
<script>
var globalNum = 10;
localNum = localNum * 10;
document.write("<p>結果は" + num + "です</p>");
var foo = true;
// 無名関数の即時実行。定義と呼び出しを同時に実行する。
(function () {
// 外側の変数 (foo) を参照できる。
if (foo) {
console.log("外部ファイルを読み出しました");
}
var localNum = 20;
function localMethod() {
// 外側の変数 (localNum) を参照できる。
console.log("localNum");
}
// 定義したメソッドを実行
localMethod();
})();
</script>
01-04. ブラウザのバージョン¶
Polyfill¶
▼ Polyfillとは¶
JavaScriptやHTMLの更新にブラウザが追いついていない場合、それを補完するように実装されたパッケージのこと。
『Polyfilla』に由来している。
02. Downloading処理¶
Downloading処理とは¶
▼ 非同期的な読み出し¶
まず、サーバーサイドからWebページ (html
ファイル、.css
ファイル、js
ファイル、画像ファイル) は、分割されながら、バイト形式でレスポンスされる。
これは、メッセージボディに含まれている。
これを優先度を基に読み込む処理。
分割でレスポンスされたWebページを、随時読み込んでいく。
そのため、各Webページの読み出しは非同期的に行われる。
Downloading処理が終了したWebページから、次のParse処理に進んでいく。
▼ Webページの要素の優先順位¶
(1)
-
HTML
(2)
-
CSS
(3)
-
JS
(4)
-
画像
Pre-Loading¶
▼ Pre-Loadingとは¶
Downloading処理の優先順位を上げるように宣言する。
優先度の高い分割Webページは、次のParse処理、Scripting処理も行われる。
そのため、JSファイルのScripting処理が、以降のimageファイルのDownloading処理よりも早くに行われることがある。
<head>
<meta charset="utf-8" />
<title>Title</title>
<!-- preloadしたいものを宣言 -->
<link rel="preload" href="style.css" as="style" />
<link rel="preload" href="main.js" as="script" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>Hello World</h1>
<script src="main.js" defer></script>
</body>
Lazy Loading (遅延読み出し)¶
▼ Lazy Loadingとは¶
条件に合致した要素を随時読み込む。
条件の指定方法には、scroll
/resize
イベントに基づく方法と、Intersection Observerによる要素の交差率に基づく方法がある。
画像ファイルの遅延読み出しでは、読み出し前にダミー画像を表示させておき、遅延読み出し時にダミー画像パスを本来の画像パスに上書きする。
▼ scrollイベントとresizeイベントに基づく読み出し¶
scrollイベントとresizeイベントを監視し、これらのイベントの発火をトリガーにして、画面内に新しく追加された要素を随時読み込む。
▼ Intersection Observerによる要素の交差率に基づく読み出し¶
Intersection Observerによる要素の交差率を監視し、指定の交差率を超えた要素を随時読み込む。
例えば、交差率の閾値を『0.5
』と設定すると、ターゲットエレメントの交差率が『0.5
』を超えた要素を随時読み込む。
Eager Loading¶
▼ Eager Loadingとは¶
02-02. Parse処理¶
Parse処理とは¶
Downloading処理によって読み込まれたWebページを翻訳するプロセス
html
形式テキストファイルの構造解析¶
▼ 構造解析の流れ¶
Downloading処理で読みこまれたバイト形式ファイルは、文字コードを基に、一連の文字列に変換される。
ここでは、以下のhtml
ファイルと.css
ファイル (style.css
) に変換されたとする。
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
<div style="width: 50%">
<div style="width: 50%">Hello world!</div>
</div>
</body>
</html>
/* style.css */
body {
font-size: 16px;
}
p {
font-weight: bold;
}
span {
color: red;
}
p span {
display: none;
}
img {
float: right;
}
Webページの文字列からHTMLタグが認識され、トークンに変換される。
各トークンは、1
個のオブジェクトに変換される。
HTMLパーサーは、オブジェクトをノードとして、DOMツリーを作成する。
DOMツリーを作成する途中でscriptタグに到達すると、一旦、JSファイルを読み込んでScripting処理を終えてから、DOMツリーの作成を再開する。
DOMのインターフェースについては、以下のリンクを参考にせよ。
同時に、CSSパーサーは、headタグにあるlinkタグを基にサーバーにリクエストを送信する。
レスポンスされた.css
ファイルに対してDownloading処理を行った後、オブジェクトをノードとして、CSSOMツリーを作成する。
xml
形式テキストファイルの構造解析¶
▼ 構造解析の流れ¶
レンダリングエンジンは、最初に出現するルート要素を根 (ルート) 、またすべての要素や属性を、そこから延びる枝葉として意味づけ、レンダリングツリーを作成する。
*例*
03. Scripting処理¶
Scripting処理とは¶
サーバーサイドからWebページ (html
ファイル、.css
ファイル、js
ファイル、画像ファイル) を取得した後、レンダリングエンジンのHTMLの解析がscript
タグに到達する。
レンダリングエンジンは、JavaScriptエンジンにscript
タグの内容を渡す。
JavaScriptエンジンは、JavaScriptコードを機械語に翻訳し、実行する。
この処理は、初回アクセス時のみでなく、イベントが発火した時にも実行される。
JavaScriptエンジン¶
▼ JavaScriptエンジンとは¶
JavaScriptのインタプリタのこと。
JavaScriptエンジンは、レンダリングエンジンからhtml
ファイルに組み込まれたJavaScriptのコードを受け取る。
JavaScriptエンジンは、これを機械語に翻訳し、ハードウェアに対して、命令を実行する。
▼ 機械語翻訳¶
JavaScriptエンジンは、コードを、字句解析、構造解析、意味解釈、命令の実行、をコード1行ずつに対し、繰り返し実行する。
03-02. イベント¶
イベント¶
▼ イベントとは¶
ブラウザの各操作はイベントとして.js
ファイルまたはhtml
ファイルに紐付けられている。
▼ イベントハンドラ関数とは¶
イベントの発火に伴ってコールされる関数のこと。
イベントハンドラ関数が実行されるたびにScripting処理が繰り返される。
html
形式におけるイベントハンドラ関数のコール¶
▼ onload
¶
『Webページのローディング』というイベントが発火すると、イベントハンドラ関数をコールする。
▼ onclick
¶
『要素のクリック』というイベントが発火すると、イベントハンドラ関数をコールする。
<input type="button" value="ボタン1" onclick="methodA()" />
<script>
function methodA() {
console.log("イベントが発火しました");
}
</script>
JS形式におけるイベントハンドラ関数のコール¶
▼ document.getElementById.onclick
関数¶
指定したIDに対して、1
個のイベントと1
個のイベントハンドラ関数を紐付ける。
*実装例*
// 指定したIDで、クリックイベントが発火した時に、処理を実行する。
document.getElementById("btn").onclick = () => {
console.log("イベントが発火しました");
};
▼ document.addEventListener
関数¶
1
個のイベントに対して、1つ以上のイベントハンドラ関数を紐付ける。
第一引数で、click
などのイベントを設定し、第二引数でメソッド (無名関数でも可) を渡す。
false
を設定することにより、イベントバブリングを行わせない。
*実装例*
<button id="btn">表示</button>
<script>
const btn = document.getElementById("btn");
btn.addEventListener(
"click",
() => {
console.log("クリックされました!");
},
false,
);
</script>
// DOMContentLoadedイベントが発火した時に、処理を実行する。
document.addEventListener("DOMContentLoaded", () => {
console.log("イベントが発火しました");
});
// 1つ目
document.getElementById("btn").addEventListener(
"click",
() => {
console.log("イベントが発火しました`(1)`");
},
false,
);
// 2つ目
document.getElementById("btn").addEventListener(
"click",
() => {
console.log("イベントが発火しました`(2)`");
},
false,
);
04. Rendering処理¶
Rendering処理とは¶
レンダリングツリーが作成され、ブラウザ上のどこに何を描画するのかを計算する。
CalculateStyle処理とLayout処理に分けられる。
04-02. CalculateStyle処理¶
CalculateStyle処理とは¶
レンダリングエンジンは、DOMツリーのルートのノードから順にCSSOSツリーを適用し、Renderツリーを作成する。
04-03. Layout処理¶
Layout処理とは¶
上記で読み込まれたhtml
形式テキストファイルには、ネストされた 2 つの div がある。
1 つ目 (親) のdiv
より、ノードの表示サイズをビューポートの幅の 50% に設定する。
この親に含まれている 2 つ目 (子) のdiv
より、その幅を親の50%、つまりビューポートの幅の25%になるようにレイアウトされる。
05. Paint処理¶
Paint処理とは¶
DOMツリーの各ノードを、ブラウザ上に描画する。
05-02. Rasterize処理¶
Rasterize処理とは¶
記入中...
05-03. CompositeLayers処理¶
CompositeLaysers処理とは¶
記入中...