🙌

ブラウザの中の処理を覗いてみよう ~第2章 ファイルの解析、レンダーツリー構築編~

2024/09/02に公開

こんにちは。

今回はブラウザ上での処理を覗いてみようということで、ファイルの解析とレンダーツリーの構築についてまとめていきたいと思います。

もうちょっと細かく言うと

  • レンダリングエンジンの DOM と CSSOM 生成
  • JS エンジンの解析、コンパイル
  • それらを合わせて構築するレンダーツリー

自分達が作成したコードがどのように実行、描画されていくかをイメージできるかと思います。

この記事は4部編成に分かれています。前回の記事に目を通しておくと理解を助けてくれますので、是非読んでいってくださいね(^^)

流れ

DOM や CSSOM の生成は、レンダリングエンジンにて行われます。

(前記事より)

この辺の処理を詳しく見ていきましょう。

HTML, CSS のダウンロード

まず、ネットワークから渡された HTML と CSS がダウンロードされます。

解析、DOM, CSSOM の生成

ダウンロードされた HTML は、Byte Code としてスタートしていきます。

最終的に DOM, CSSOM へ変換していくわけですが、いくつかの過程を踏んでいきます。

以上の過程を踏んでいきます。詳しく見ていきましょう。

Conversion: Byte Code→Characters

まず、ダウンロードした HTML は人間が書いたコードではなく、Byte Code という命令の塊のような形式になっています。

この Byte Code を人間が読める形式に加工していきます。

特に意味をなさず、ただの文字列といったニュアンスです。

その際、文字コードという情報に基づいて変換していくことを頭の片隅に置いておくと良いでしょう。

Tokenizing: Characters→Tokens

Characters に変換された HTML は、構造的に意味のある情報に変換する必要があります。

そのため、Token という塊にまとめていきます。

例えば<から>までの文字は開始タグで、</で始まっているのは終了タグだ。といった具合で塊を作っていきます。

その際、W3C HTML Standerdという解析上の規約があり、そのルールに基づいて Tokens に変換していくようです。

Lexing: Tokens→Nodes

構造的に意味のある Token に変換された次は、DOM を生成するためにオブジェクトへ変換していきます。

Token の性質によって様々な種類の Node(オブジェクト)を生成していきます。

Document や Element など、様々な種類のオブジェクトが存在するのですが、こちらで詳しく確認できます。

DOM construction: Nodes→DOM

種類ごとに分けられた Nodes から、DOM を構築していきます。

ツリー構造になっているのがポイントですね。

こちらの DOM、JS を使って操作したり参照したりできます。

JS で DOM 操作をすることによって DOM が動的になっていくのですね!

CSSOM も同様にして生成されていきます。

以上の解析処理を Parse というので、覚えておくと良いかもしれません(^^)

script タグがあった際、記述されたコードを JS エンジンに渡す

HTML の解析中に script タグがあった場合、レンダリングエンジンは JS の解析ができませんので、JS エンジンに処理を任せていきます。

JS エンジンの処理の流れを見ていきましょう!

JS コードの解析、コンパイル

文字列を出力するコードを例に解説していきます。

console.log('HogeHoge');

字句解析: コード →Token

渡されたコードを一文字ずつ読み込んでいき、プログラム的に意味のある最小単位に切り分けていきます。

先ほど Characters から Tokens への変換について解説しましたが、それと似ています。

構文解析: Token→AST

次に、生成した Token から、抽象構文木(AST)というツリー構造を生成していきます。

DOM と似たもので、コードがどんな構造をしているかを把握できます。

console.log('HogeHoge');

type: Program
-
body
-
#1
type: ExpressionStatement
-
expression
type: CallExpression
-
callee
type: MemberExpression
computed: false
-
object
type: Identifier
name: console
-
property
type: Identifier
name: log
-
arguments
-
#1
type: Literal
value: HogeHoge
raw: 'HogeHoge'
sourceType: script

下記のリンクは、ご自身の書いたコードを即座に AST に変換してくれるサイトですので、ぜひご確認ください。(Token も確認できます)

https://esprima.org/demo/parse.html?code=%2F%2F Life%2C Universe%2C and Everything console.log("Hello World !")%3B

(ESLint は AST を経由して構文エラーや警告などを表示してくれるらしいですよ!)

コンパイル: AST→Byto Code

生成した AST をコンパイルすることによって、CPU が処理できるようにしていきます。

実は JS エンジンによってコンパイルのタイミングは違います。解析が終わったタイミングでコンパイルするエンジンもあれば、JS を実行するタイミングでコンパイルすることもあります。(現在の段階ではまだ解析が終わった段階。コードの実行はしていない)

最近は JIT コンパイルという、中間言語に翻訳して実行時に素早くコンパイルするといった方式が使われているようです。驚き!

JS の実行

コンパイルされた JS が CPU にて実行されます。

(実行時の話題として絶対外せないイベントループについては、次の章で解説します)

実行した JS の結果と DOM, CSSOM を元にレンダーツリーを構築

最後に、生成した DOM と CSSOM を元に、レンダーツリーを構築していきます。

DOM による構造的な情報と、CSSOM による付随的な情報をあわせ、新しいツリー構造を作っていきます。

DOM に CSSOM の情報が加わったというニュアンスで良いと思います。(私はそういう認識です)

以上が画面描画時のレンダリングエンジンと JS エンジンの処理の流れです。

次は、実行された JS がどのように動いていくのかを解説していきます。イベントループの仕組みを理解することで、JS が超絶強くなる様をみていきましょう(^^)

最後まで読んでくださり、ありがとうございました!

Discussion