Closed40

私は雰囲気でブラウザを使っています。

hajimismhajimism

ブラウザの基礎知識がほしいのでそれっぽい記事を読んでいくだけのスクラップ

hajimismhajimism
hajimismhajimism

まずざっくり流れを把握

  1. URLを解読する
  2. HSTSリストを調べる
  3. DNSでIPアドレスを取得する
  4. ポート番号の指定
  5. HTTPリクエストの送信
  6. ロードバランサー通過
  7. HTTPレスポンスの送信
  8. HTMLのレンダリング
  9. JSONデータの取得
hajimismhajimism

参考資料リスト

What happens when...
ウェブサイトが表示されるまでにブラウザはどういった仕事を行っているのか?
ネットワークはなぜつながるのか
Webフロントエンド ハイパフォーマンスチューニング
Webサイト表示の流れをざっくりとまとめた。 | ただ屋ぁのブログ
What happens when you type a URL in the browser and press enter?
日経XTECH DNSの歴史(第1回 「HOSTSファイルの崩壊」)
知っておきたいロードバランサーの基礎技術

hajimismhajimism

URLを解読する

URLを分解して、「プロトコル」と「ドメイン名」と「パス名」が何であるかを調べます。

もしプロトコルの記述がなかったり有効なドメインではなかった場合、ブラウザは入力されたテキストをブラウザのデフォルトの検索エンジンに渡します。

hajimismhajimism

HSTSリストを調べる

HSTS ( HTTP Strict Transport Security ) とは、超簡単にいうとユーザーが http でアクセスしようとしてきたとき、ブラウザが自動で https に置き換えてアクセスしてくれる機能のことです。

同じ作者の方が別の記事で詳述している
https://zenn.dev/ak/articles/dfaa9e01b374a0

hajimismhajimism

DNSでIPアドレスを取得する

といってもすぐにDNSに問い合わせるわけではなく、近いところから順番に探しに行く。

  1. ブラウザのキャッシュ
  2. hostsファイル
  3. キャッシュDNSサーバ(スタブリゾルバからの問い合わせ)
  4. ネームサーバ(キャッシュDNSサーバからの問い合わせ)

HOSTS.TXTが使われていた当時 ( 1970年代 ) では、わずか数百台のホストしかなかったので、ネット上の全てのホスト情報の記載が可能でした。

しかし、インターネットが普及していくにつれてHOSTS.TXTは肥大化していき、1983年には、ホスト数はおよそ数万台になりました。もはやHOSTS.TXTによる名前解決は不可能となったので、現在のようなDNSサーバを設置して名前解決する仕組みが生み出された、という流れです。

おもろい

もしキャッシュDNSサーバに client.sharefull.com の問い合わせ結果のキャッシュがなかったら、キャッシュDNSサーバは、スタブリゾルバの代わりに 「ルートネームサーバ」 → 「.comのネームサーバ」 → 「sharefull.comのネームサーバ」 へと順に問い合わせを行います

層ごとにリクエストする場所が違う

そして、IPアドレスが分かったら、スタブリゾルバに「IPアドレスわかったよ〜」という問い合わせ結果を返します。スタブリゾルバは、問い合わせ結果からIPアドレスを取り出して、ブラウザから指定されているメモリー領域に書き込みます。

あくまでブラウザはスタブリゾルバとやり取りしているんだな

hajimismhajimism

ポート番号を指定する

ポート番号 とは、TCP/IPにおいて、同じコンピュータ内で動作する複数のソフトウェアのうち、どれと通信するのか指定するための番号のことです。

IPアドレスを「電話番号」と例えるならば、ポート番号番号は電話をかけたときに「○○さんをお願いしたいのですが」と言って、話す相手を呼び出すような仕組みです

わかりやすいたとえ

私たちがブラウザでURLにポート番号を入力しなくてもWebサイトにアクセスできるのは、スキームを見て「http:」だったら80番、「https」だったら443番というように、自動的にポートを割り当てているからです。

hajimismhajimism

HTTPリクエストの送信

さあ盛り上がってまいりました。

HTTPリクエストは「リクエストライン」と「ヘッダー」と「メッセージボディ」というフォーマットで作成されるらしいです...

リクエストの構成をわかりやすいように図で表すと、以下のようになります。

わかりやすい図

hajimismhajimism

ロードバランサー

Webサービスにおいて、1台のサーバのみで運用するとアクセス集中でサーバがダウンしたときなど、サービス停止に追い込まれてしまうので、複数サーバを用意するのが一般的です。

ロードバランサーは、これら複数台のWebサーバを束ねて、Webサーバに来たリクエストをバランス良く振り分ける装置のことを言います。

ロードバランサーの有能な機能として、サーバの状態を把握する ヘルスチェック と、同じクライアントのリクエストを継続的に同一のサーバに振り当てる セッション維持 というのがあります。

  • ヘルスチェック:サーバーの異常を検知し、異常なサーバーを回避して正常なサーバーにリクエストを割り振るようにする
  • 同一ユーザーからのアクセスは同じサーバに振り分ける

ログインできるのはロードバランサーのおかげでもあったのかー!

hajimismhajimism

HTMLのレンダリング

ブラウザレンダリングには、大きく分けて4つのフェーズがあります。

  • Loading
    • 描画に必要なリソースの読み込み
    • 最初にHTMLファイルを上から順に読み込み、途中でCSSやJavaScriptや画像などの外部のリソースを発見するたびにサーバにリクエストする
    • 読み込まれたリソースは扱いやすいかたちに変換される(eg. HTMLはDOMツリーに、CSSはCSSOMツリーに)
  • Scripting
    • 字句解析 → 構文解析 → コンパイル→JS実行
    • プログラムの途中でAPI呼び出しの処理があればサーバにリクエストする
hajimismhajimism
hajimismhajimism

全体像

  1. HTMLのダウンロード
  2. HTMLの解析
  3. CSSのダウンロード
  4. CSSの解析
  5. JSのダウンロード
  6. JSの実行
  7. レンダーツリーの構築
  8. Layout
  9. Painting
hajimismhajimism

HTMLの解析

送られてきたデータを以下の流れでDOMにParseする。

  1. Content-Typeヘッダーまたはmetaタグで指定された文字コードに基づいて、未加工のバイトから人間が読める文字 ( Characters ) に変換する
  2. Charactersを一定単位ごとにTokensに変換する
  3. Tokensからより扱いやすいインターフェイスを持ったNodesに変換する
  4. NodesをもとにDOMを構築する
hajimismhajimism

CSSの解析

linkタグからcssを見つけたら、HTMLの解析と同じ流れでCSSOMを構築する。

スタイルはカスケードする。ブラウザごとにuser agent stylesheetというデフォルトスタイルの設定がある。

hajimismhajimism

JavaScriptの実行

JSを機械語に落とし込む必要がある。一連の流れ↓

字句解析と構文解析はHTMLのCharacters〜Nodesと大体一緒。JSの場合、抽象構文木はJSONで表現される。このJSONを機械語にコンパイルしていく。

コンパイル方法にはいろいろあるが(要調査)、V8エンジンはJITコンパイラを利用しているらしい。
↓これ読みたい。

JITコンパイラについてもっと知りたい方は、こちらの記事が分かりやすくておすすめです。

A crash course in just-in-time (JIT) compilers
How does JavaScript and JavaScript engine work in the browser and node?

↓は読んだ。この記事で説明されていることの他に、byte codeになったあとにさらにOptimizeしていることがわかった。動的型付けと静的型付けでOptimizeの手間が異なりそう。

また、こちらはJavaScriptエンジンの仕組みを解説した記事です。GIFアニメでとても分かりやすいです。
🚀⚙️ JavaScript Visualized: the JavaScript Engine

hajimismhajimism

レンダーツリーの構築

???: I hove a DOM~
???: I hove a CSSOM~
???: ドッドッ ん’’ーっ!!
???: What a beautiful Render Tree

ということらしい。display: noneされてたりする、レンダリングに不要なものは上手いこと除くのだと。

hajimismhajimism

Compositing

Layoutの計算が行われ、Paintingの順番を決めた後、一定のLayerごとにピクセルを描画していく。

色々計算の工夫をしながら最終的にはComposite Layersなるものを作成し、そいつをGPUに送ることで画面を描画している。

hajimismhajimism
hajimismhajimism
  • ブラウザエンジン
    • UIとレンダリングエンジンの間の処理を整理
  • レンダリングエンジン
    • 要求されたコンテンツ(HTMLなど)の表示を担当
hajimismhajimism

④ Painting the render tree

ようやく描画します。
どこに描画するかという配置方法について考えることになります。
大きく分けて、3つに分かれます。

通常
オブジェクトはドキュメント内の場所に従って配置されます。つまり、レンダーツリー内の場所はDOMツリー内の場所と同様になり、ボックスの種類や寸法に従ってレイアウトされます。
position:static,relative

フロート
オブジェクトは最初に通常のフローのようにレイアウトされてから、左右のできるだけ遠くに移動されます。
float:right,left

絶対
オブジェクトはレンダーツリー内でDOMツリーとは異なる場所に配置されます。
position:absolute,fixed

hajimismhajimism

大枠は上で見てきたこれの話だな。これが基礎知識だったっぽい。

hajimismhajimism
hajimismhajimism

全体像

この記事はクライアント側のキャッシュの話をしてくれるらしい。

hajimismhajimism

インメモリキャッシュ

インメモリキャッシュはRAMに保存されるため、書き込みとアクセスが高速になりますが、コンピュータの電源がオフになるか、その他の特定の状況で消去されます。このインメモリキャッシュは、各ブラウザのRendererプロセスに存在しています。

また、LRU方式でキャッシュが削除されていることがわかります

LRU方式ってなんだろうと思って調べた。Least Recently Usedの略らしい。

LRUとは、広さの限られた一時的な保管場所が満杯になったとき何を棄てるか決定する基準の一つで、最も過去に使用されたものから順に破棄する方式。IT分野以外でも書類の整理方法などに応用されている。(IT用語辞典

余談にはなりますが、Chrome97でも完全に導入されたBack/Forward Cacheも、このインメモリキャッシュにあたります。

Back/Forward Cacheはページ遷移の前後をキャッシュしてくれる機構らしい。

bfcache is an in-memory cache that stores a complete snapshot of a page (including the JavaScript heap) as the user is navigating away. With the entire page in memory, the browser can quickly and easily restore it if the user decides to return.

How many times have you visited a website and clicked a link to go to another page, only to realize it's not what you wanted and click the back button? In that moment, bfcache can make a big difference in how fast the previous page loads:(web.dev

毎度思うけどアルゴリズムがわかんないと具体的にイメージできない

hajimismhajimism

ServiceWorkerキャッシュ

そしてServiceWorkerは、Cache Storage API もしくは、IndexedDBを用いて、リソースのキャッシュを行います。ServiceWorkerが他のキャッシュと大きく違うのは、HTTPをinterceptして、キャッシュの操作をプログラマブルに行うことができるという点です。

...ServiceWorkerキャッシュは、オフライン時のユーザー体験をより良くすることにのみ利用しています。

PWAの話とつながりそう

ServiceWrokerキャッシュを操作する際には、直接WebAPIを使うことは珍しく、多くの場合はWorkBoxのようなラッパーを利用することが一般的だと思います。

WorkBoxってどっかで見たことあるな...ServiceWrokerのライブラリだったか。

hajimismhajimism

ブラウザキャッシュ

  • Browserプロセスに存在している
  • (HDDやSSDといった)ストレージに書き込まれるため、半永久的に残る
  • 読み取りと書き込みに時間がかかる

RFC7234で定められているらしい

hajimismhajimism

上の方で読んだ記事のおかげで、IPアドレスを取得するまでにも色々キャッシュがあることがわかる。

hajimismhajimism

ついでにPWAもちょっと覗く
https://zenn.dev/mi_/articles/498a82a0efa0ff

hajimismhajimism

PWAとは何かをざっくりと説明すると、ネイティブアプリと Webの良いとこどりしたもので、
より良いUXを提供できるWebアプリケーションを目指しています。

hajimismhajimism

A2HS Mini-infobar を実装手順
manifest を設定する
Service Worker を導入する
デプロイ

これはなんとなく知ってる

hajimismhajimism

最近では各種フレームワークが、そのフレームワークに適した Service Worker を作るためのライブラリを用意していることも少なくありません。

Gatsbyだとプラグインが全部やってくれる

このスクラップは2023/01/22にクローズされました