こんにちは。チームのパフォーマンスチューニングを任されると、避けて通れないのが「ブラウザの裏側の挙動」の理解だよね。
「なぜかウチのサイト、初期表示がもたつくんだよね……」
「 Lighthouseのスコアを改善したいのに、どこから手をつけていいか分からない」
そんな相談を後輩から受けるたびに、私は決まってこう聞き返すんだ。「ねえ、ブラウザが裏側でどうやってHTMLを読んでいるか、想像したことある?」ってね。
画面が真っ白なままフリーズしているように見える時間、実はブラウザのエンジンは水面下ですさまじいバトルを繰り広げている。今回はその中でも、「投機的パース(Speculative Parsing)」という、ブラウザが編み出した最高に泥臭くて美しい最適化アルゴリズムについて、実務の視点から徹底的に解説しようと思う。
—
1. そもそも「投機的パース」とは何か?
ブラウザのメインスレッドは実に多忙だ。HTMLを上から順にパース(解析)し、DOMツリーを作り、CSSOMを作り、レイアウトを計算し、ペイントする。
ここで、フロントエンド開発者なら誰もが知る「あの悪夢」を思い出してほしい。
HTMLの途中に、同期的な `` が現れた瞬間、何が起きるか?
そう、「レンダリングブロック(Rendering Blocking)」だ。
JavaScriptの実行が完了するまで、ブラウザは次のHTMLをパースできなくなる。もしこのスクリプトの裏で、外部のCSSや巨大な画像、さらなるJavaScriptの読み込みが必要だったらどうなるだろう? メインスレッドが塞がれている間、ネットワーク帯域が完全に遊んでしまう。これじゃあブラウザとしてあまりにも非効率だよね。
そこで登場するのが、投機的パース(Speculative Parsing / スプレキュラティブ・パース)だ。
裏側で何が起きているのか?
ブラウザ(例えばChromiumであればBlinkエンジン)は非常に賢い。メインスレッドがJavaScriptの実行やDOM構築でブロックされているまさにその瞬間、「別スレッド(Lookahead Preparser)」を裏でこっそり起動する。
そして、メインスレッドが止まっているのを横目に、HTMLのテキストを先読み(スキャン)し、「おっと、この先に画像やCSS、他のスクリプトがありそうだぞ」と、リソースのURLを未来予測(投機)して、先回りしてダウンロードを始めるんだ。
まさに、チェスの名手が相手の駒が動く前に先読みして次の一手を準備しているようなものだね。この仕組みのおかげで、ネットワークのアイドルタイムが極限まで削減され、体感速度が劇的に向上している。
—
2. 実務で直面する「投機的パースの罠」
この投機的パース、めちゃくちゃ優秀な機能なんだけど、「書き方一つでその恩恵を受けられなくなったり、逆に足を引っ張られたりする」という裏の顔がある。
中級からシニアへステップアップするエンジニアが知っておくべき、実務上のポイントをいくつか共有しよう。
トラップ1:動的に生成されたスクリプトは先読みできない
Lookahead Preparserは、あくまで「静的にHTMLに書かれているマークアップ」をテキストとして先読みする。つまり、JavaScriptの実行によって後からDOMに挿入されるリソース(いわゆるClient-Side Rendering的なアプローチや、一部の古いサードパーティタグマネージャーのインラインスクリプト)は、投機的パースの対象外になりやすい。
トラップ2:CSSのブロックとJavaScriptの順序問題
投機的パースが画像やスクリプトを先読みしてくれるのは、「CSSOMの構築がブロックされていない場合」や「適切な順序で記述されている場合」だ。もし、`
` の中で無秩序にスクリプトとスタイルシートが入り乱れていると、Preparserがうまく機能せず、ネットワークの並列ダウンロードのメリットがスポイルされてしまう。—
3. 実践:投機的パースを最大化するためのコードパターン
では、このブラウザの最適化アルゴリズムを味方につけて、リソースのプリロードを極限までスムーズにするための実践的なHTMLの書き方を見ていこう。
現場ですぐに使える、パフォーマンスを考慮したヘッダー周りのサンプルコードだ。
Webパフォーマンスの極意
ここにメインコンテンツが入ります。
このコードのポイント(シニアからの解説)
1. `` の活用
ブラウザの投機的パースは優秀だが、HTMLの奥深くにあるリソース(例えばCSSから読み込まれる背景画像や、JSの奥で動的にロードされるモジュールなど)を発見するまでにタイムラグがある。`preload`を使うことで、PreparserがHTMLをスキャンするよりもさらに早く、ブラウザのパーサーに「これを最優先で取ってこい」と指示できる。
2. `async` と `defer` の徹底
タグにこれらの属性をつけることで、メインスレッドのブロックを防ぎつつ、Preparserが裏でネットワーク帯域をフル活用してファイルをダウンロードし続けることができる。ここをサボると、投機的パースの効果が半減してしまうんだ。
—
4. まとめ:ブラウザと「対話する」フロントエンドへ
Webブラウザは、私たちが書いたコードをただ機械的に解釈しているわけじゃない。今回紹介した「投機的パース」をはじめとして、裏側であらゆる予測や最適化を自律的に行っている。
優秀なフロントエンドエンジニアというのは、「ブラウザが次に何をしようとしているか」「どうすればブラウザの最適化アルゴリズム(Preparserなど)をスムーズに働かせられるか」を常に逆算してコードを書ける人のことだ。
ただ動くコードを書くだけのフェーズを抜け出して、ブラウザのエンジンと対話するような気持ちでマークアップやリソース設計を行ってみてほしい。サイトのスピードが劇的に変わる瞬間を実感できるはずだ。
それじゃあ、次のレビュー会でもっと面白いパフォーマンス改善の知見をシェアし合おうぜ!

コメント