はじめに
冬が来て毎日起きるのが辛いです。
面接ラッシュな中DOMを勉強し続けます。
HTMLがDOMになるまでの過程を勉強します。
HTMLがDOMになるまでの流れ
HTMLファイルは単なる「テキスト」。
ブラウザはこのテキストを解析 => DOMツリーを構築する。
HTMLバイト列 =①=> 文字列 =②=> トークン =③=> ノード =③=> DOMツリー
イメージのつきやすい画像⬇️
https://web.dev/articles/critical-rendering-path/constructing-the-object-model?hl=en
①HTMLバイト列から文字列
ネットワークから受け取るHTMLは、「テキスト = バイト列」。
まずこれを文字列に変換する。
文字列 = 文字が連続して並んだもの
バイト列 = 意味や形式に囚われず0から255までの数値データ(バイト)が連続して並んだもの
⬇️ブラウザがHTMLファイルの文字エンコーディング(バイトの並びがどのように解釈されるかを定める)を決定するときの優先順位
1位. HTTPヘッダのContent-Type
2位. BOM(Byte Order Mark)
3位. <meta charset="...">
4位. <meta http-equiv="Content-Type" content="..."> (古いやつ)
5位. 自動判定
6位. デフォルト(UTF-8)
バイト列: 3C 70 3E E3 82 84 E3 81 BB 3C 2F 70 3E
=>文字列: < p > や ほ < / p >
②文字列からトークン(トークン化)
文字列 = 文字が連続して並んだもの
トークン = 特定の価値や権利、情報を代替するデータや記号 = 意味を持つ最小単位のもの
ってことは、トークン化 = 文字に意味を持たせる
<div class="container">Hello</div>
<div class="container">Hello</div>
├─ "<" を見た → 「タグだ!」
├─ "div" を見た → 「タグ名は divだ!」
├─ "class=..." を見た → 「属性があるゾ!」
├─ ">" を見た → 「タグ終わり!」→ StartTagトークン発行
├─ "Hello" を見た → Characterトークン発行
├─ "</div>" を見た → EndTagトークン発行
- DOCTYPE(もしあれば)
- StartTag: div
(Attribute: class="container")
- Character: Hello
- EndTag: div
- EOF
トークン化を行うのは何者?
=> トークナイザ = 状態マシン(state machine)
文字を1つずつ読みながら状態を遷移させていく。
状態ってなんやねん
=> 以下のようなものたち
・Data state:通常のテキストを読んでいる("Hello" を見てる)
・Tag open state:<を読んだ直後(「タグだ!」)
・Tag name state:タグ名を読んでいる(「タグ名は divだ!」)
・Attribute name state:属性名を読んでいる
・Attribute value state:属性値を読んでいる
メモ⬇️ :状態マシンの説明(わかりやすい)
https://qiita.com/saltheads/items/8331e14f4d3b37f511aa
メモ⬇️ :トークン化詳しく(死ぬほど読みづらいbut詳しい)
https://triple-underscore.github.io/HTML-parsing-ja.html#data-state
③トークンからノード(同時にDOMツリー)
トークン = 意味を持つ最小単位(StartTag, EndTag, Characterなど)
ノード = DOMツリーを構成する1つ1つの部品
トークン = 解析結果
ノード = 実際のオブジェクト
トークン ノード
─────────────────────────────────────────
StartTag: div => Element: <div>
Character: Hello => Text: "Hello"
EndTag: div => (新しいノードは作らない)
EndTagの役割は?
EndTagは「このノードの中身はここで終わり」という合図。
「今見ているノード = 現在地」を親に戻す。
1. StartTag: div → Elementノード作成(📍現在地)
2. Character: Hello → 現在地(div)の「子」としてTextノード追加
3. EndTag: div → 現在地を親に戻す(divの中身終わり)
補足:scriptタグとパース
<script>タグはJavaScriptを読み込むためのタグ。
<script src="app.js"></script>
ブラウザはこのタグに出会うと「パース = HTML → DOMツリーの処理」を止めてJavaScriptのダウンロードと実行を待つ。
<p>Hello</p>
<script src="app.js"></script> <= ここで止まる
<p>World</p> <= app.jsが終わるまでDOMに追加されない
defer と async = パースが止まるのを避ける。
どうやって?
deferとasyncは両方パースと外部ファイルのダウンロードが同時進行で行われる。
2つの違いは?
defer = パースが全部終わってから実行
async = ダウンロード終わった瞬間に実行(パースの途中でも割り込む)
メモ⬇️:わかりやすい図とわかりやすい説明
https://qiita.com/phanect/items/82c85ea4b8f9c373d684
まとめ
「状態マシン」めっちゃ面白い
もっと勉強してみたい
状態マシン、状態機会、ステートマシン,,,,,,
どれが正しいんですか!!!!!!!
参考文献
- HTML Standard - Parsing HTML documents - WHATWG
- How Browsers Work: Behind the scenes of modern web browsers - HTML5 Rocks
- Building the DOM faster: speculative parsing, async, defer and preload - Mozilla Hacks
- MDN Web Docs - DOMParser - Mozilla
- MDN Web Docs - defer attribute - Mozilla