ブラウザ
画面が描かれる仕組みと、その上の制約
ブラウザは HTML を受け取ってから描画するまでに決まった工程を通る。どの CSS プロパティを触ると工程のどこからやり直しになるか、なぜ非同期処理が「詰まる」のか。そして、そこに被さる同一オリジンという安全装置。
読み終わると、これに答えられるようになります
- ?top を書き換えると重く、transform だと軽いのはなぜか
- ?重い処理中にクリックが効かなくなるのはなぜか
- ?CORS エラーはサーバーとブラウザのどちらが出しているのか
レンダリングパイプライン — どのCSSが重いかは工程で決まる
ブラウザが HTML を受け取ってから画面を描くまでの工程。どのプロパティを触ると、どの工程からやり直しになるのか。
スクロール連動アニメーションで top を毎フレーム書き換え、スマホで完全に固まった
イベントループ — 1本のスレッドで待たずに捌く
JavaScript が1スレッドなのに、なぜ複数の処理を同時に進められるのか。そして、なぜ「重い処理」が画面ごと止めるのか。
10万件の配列を同期でループし、その間ボタンもスクロールも一切反応しなくなった
同一オリジンポリシー — ブラウザが最初から持っている壁
なぜ他のサイトの JavaScript から自分のページのデータを読めないのか。この制約がなければ Web はどうなっていたか。
iframe で埋めた別ドメインの画面を JS から操作しようとして、原因不明のエラーで1日溶かした
CORS — 壁に穴を開けるのは「読まれる側」
プリフライトはなぜ飛ぶのか。ワイルドカードと Cookie が同時に使えないのはなぜか。エラーメッセージから原因を逆算する。
CORS エラーを直そうとフロント側の fetch オプションを1日いじり続けた
ブラウザのストレージ — 読めるか、と、送られるかは別の話
Cookie / localStorage / sessionStorage / IndexedDB を容量ではなく「誰が読めて、いつ送られるか」で分ける。認証情報の置き場所を決めるための判断軸。
アクセストークンを localStorage に置き、外部スクリプト経由で持ち出されて8時間なりすまされた
Core Web Vitals — 数字を上げるのではなく、何が遅いかを特定する
LCP・INP・CLS は原因ではなく症状の分類。3つが何の代理指標なのかを知ると、直す場所が工程の中で決まる。
LCP の数字だけを追って画像を軽くしたが、遅さの原因は別の工程にあった
Service Worker — 直したのに、利用者の画面だけ古い
修正をデプロイしたのに、一部の利用者だけ古い画面のまま壊れた API を叩き続ける。ブラウザとネットワークの間に、自分で書いたプロキシがもう1枚挟まっている。
修正をデプロイしたのに、一部の利用者だけ3日間、古い画面のまま消えた API を叩き続けた
画像と動画の配信 — 軽くしたはずの画像が、ページを遅くしている
全部の画像を WebP にして遅延読み込みを付けたら、LCP が悪化した。効くのは形式より画素数で、遅延読み込みは付ける場所を間違えると逆に遅くする。
画像を全部 WebP にして遅延読み込みを付けたら、商品ページの LCP が 2.1秒から 3.4秒に悪化した
アクセシビリティ — div にクリックを付けた日から、誰かが使えなくなる
見た目は完璧なボタンを作った。キーボードでは押せず、読み上げでは「何か」としか読まれない。button と書けば全部付いてきたものを、自分で捨てていた。
div で作ったボタンが、キーボードでも読み上げでも操作できなかった
描画をどこでするか — HTML を作る時と場所を、データごとに選ぶ
初回の表示が遅いので、全ページをサーバーで描画するようにした。セールの日、1 日 1 回しか変わらない商品説明を、アクセスのたびに描き直してサーバーが落ちた。方式はアプリ単位ではなく、データの鮮度と、誰のものかで決まる。
初回表示の遅さを直すため全ページをサーバー描画にしたら、セールの日に 1 日 1 回しか変わらないページまで毎回描き直してサーバーが落ちた
再描画はなぜ起きるか — 1 文字打つたびに、表ぜんぶが描き直されていた
検索欄に 1 文字打つたびに、画面が 0.4 秒固まった。メモ化を全部の部品に付けても変わらなかった。描き直される範囲は、状態を持つ場所で決まる。
検索欄に 1 文字打つたびに 5,000 行の表が描き直され、入力が 0.4 秒ずつ遅れた。メモ化を全部に付けても直らなかった
データをどこで取るか — 取得が一列に並ぶと、画面は足し算で遅くなる
注文の詳細画面が 2.4 秒かかっていた。API はどれも 0.8 秒で返っていた。部品がそれぞれ、自分が描かれてからデータを取りに行っていたので、3 回の待ちが順番に並んでいた。
3 つの API はどれも 0.8 秒で返るのに、部品ごとに順番に取りに行っていたため、注文の詳細画面が 2.4 秒かかった
フォームと入力の検証 — 画面の検証は親切、サーバーの検証は守り
申し込みフォームで、送信ボタンを 2 回押した人に申し込みが 2 件でき、エラーで戻った人の入力は全部消えていた。画面の検証を足しても、サーバーを通る値は守れない。役割の違う 2 つの検証を、別のものとして設計する。
申し込みフォームで二重送信の申し込みが月 40 件でき、エラーで戻ると入力がすべて消えていた。画面の検証をすり抜けた不正な値も DB に入っていた