Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ブラウザの制約条件から考えるフロントエンドのリソース設計/Frontend Performan...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
forrep
September 26, 2019
Programming
900
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ブラウザの制約条件から考えるフロントエンドのリソース設計/Frontend Performance How to
forrep
September 26, 2019
More Decks by forrep
See All by forrep
サービスに組み込むAIのパターン/アンチパターン
forrep
0
140
Linux && Docker 研修/Linux && Docker training
forrep
28
5.8k
RAGにベクトルDBは必要ない!DBも不要で運用めちゃ楽な RAG Chatbot を作った話
forrep
38
18k
Google Analytics でサイト速度を計測する / Measure site speed with Google Analytics
forrep
2
450
最近コードレビューで指摘したこと
forrep
4
630
「プログラマーのためのCPU入門」は入り口として丁度よい!
forrep
54
38k
DevTools でパフォーマンスチューニング入門 / Introduction to Performance Tuning with DevTools
forrep
2
550
技術的負債に対する視力を得る / How to View Technical Debt
forrep
0
950
しくじり先生 - NFS+sqliteで苦労した話から学ぶ、問題解決の考え方 / problem-solving approach
forrep
1
1.4k
Other Decks in Programming
See All in Programming
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
420
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
170
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
540
Foundation Models frameworkで画像分析
ryodeveloper
1
600
php-fpmのプロセスが枯渇した日-調査・対処・そして本当にやるべきだったこと-
shibuchaaaan
0
240
OpenSpecのproposalにbrainstormingを持たせてみた
tigertora7571
1
200
VibeCodingからAgenticWorkflowへ
starfish719
0
300
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
20260722_microCMSで考える、AI時代のコンテンツ運用設計
yosh1
0
370
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
570
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
240
Apache Hive: そしてCloud Native Lakehouseへ
okumin
1
210
Featured
See All Featured
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
270
Design in an AI World
tapps
1
270
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Producing Creativity
orderedlist
PRO
348
40k
Embracing the Ebb and Flow
colly
88
5.1k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.7k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
730
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
It's Worth the Effort
3n
188
29k
Transcript
ブラウザの制約条件から考える フロントエンドのリソース設計 ~ブラウザができること、できないこと~ 1 株式会社ラクーンホールディングス 羽山 純
自己紹介 2
• 名前 ◦ 羽山 純 • 所属 ◦ 株式会社ラクーンホールディングス 技術戦略部
• 技術領域 ◦ サーバーサイド開発 ◦ パフォーマンス改善 ◦ AI開発 (企業審査のAI) • 趣味 ◦ 旅行(ダイビング) ◦ アプリ開発 ? 自己紹介 3
ラクーンホールディングスとは? 事業者間取引(BtoB)の領域で問屋のECサイトや 決済サービス・保証事業を展開 Ruby bizグランプリ2017 「Fintech賞」を受賞 Ruby biz 2017 4
講演について 5
講演について 本日の講演は 以下の寄稿記事をベースとしています。 Software Design 2019年10月号 "速い"Webアプリケーションの作り方 フロントエンド編 「第2章 パフォーマンスを落とさないリソース設計」
本日の講演を面白いと感じていただけた方は 是非、本誌も手に取っていただけたらと思います。 6
デモ環境について 7
デモ環境について 本日はデモ環境で実際に動かしながら進めます。 Node.js製の簡易ウェブサーバを利用します。 https://github.com/forrep/web-performance 覚えておくルールは1つだけ。 ファイル名パターンで転送遅延させてます。 hoge.html ⇒ 遅延なし hoge_10s.html
⇒10秒遅延してから転送(TTFB =10秒) hoge_10s_g.html ⇒10秒間で徐々に転送(TTFB = 0秒) 8
デモ環境について 実際に試してみたい方 ※Node.js v4以降が必要、追加ライブラリ不要 本日のイベントで利用する環境には以下のURLで アクセスできます。 http://localhost:8080/event/ 9 $ git
clone https://github.com/forrep/web-performance.git $ cd web-performance $ node server.js Starting on http://localhost:8080
では、始めましょう 10
DOM(Document Object Model)構築とは • HTMLをブラウザがパースしてDOMを構築する • 構築されたDOMは、そのまま画面に表示される • このHTMLファイルを10秒で徐々に転送してみる <!DOCTYPE
html> <head> <meta charset="utf-8"> <title>巨大なHTMLドキュメント</title> <style> body { font-size: 5pt; } </style> </head> <body> <span>▪</span> <span>▪</span> <span>▪</span> <span>▪</span> ・ ・ <span>▪</span> </body> 10,000行 11
DOM(Document Object Model)構築とは デモを見る ※ 2. 巨大なHTMLを10秒で徐々に転送 12
DOM(Document Object Model)構築とは DOM構築 = 画面表示 DOM構築されたら、 即時に画面表示されます。 (実は半分ウソ、真実は後述) 13
JavaScriptとDOM構築のブロック • <script>タグで外部JavaScriptを読み込む。 • <script>読み込みでサーバー側の遅延処理が入る、 転送に5秒間かかる。 <!DOCTYPE html> <head> <meta
charset="utf-8"> <title>03 JavaScriptはDOM構築をブロック</title> </head> <body> <div>この文章はすぐに表示される。</div> <script src="time_5s.js"></script> <div>この文章はJavaScriptが実行された後(5秒後)に表示される</div> </body> 14 time_5s.js ⇒ 5秒遅延
JavaScriptとDOM構築のブロック • time.js は以下の内容で、実行した時間を <body>に「Exec: ◦◦sec」と追記するだけ。 (function() { var tag
= '<div style="color: red;">Exec: ' + (performance.now()/1000).toFixed(2) + 'sec</div>'; var insertTag = function() { document.body.insertAdjacentHTML('beforeend', tag); }; if (document.body) { insertTag(); } else { document.addEventListener("DOMContentLoaded", insertTag); } })(); 15 <body>のDOMを構築済みならそのまま追記 <body>のDOMが未構築なら DOMContentLoadedのタイミングで追記
JavaScriptとDOM構築のブロック デモを見る ※ 3. JavaScriptとDOM構築のブロック 16
JavaScriptとDOM構築のブロック HTML転送 ≠ DOM構築 = 画面表示 <script>はDOM構築をブロックする 「HTML転送済み」≠「DOM構築済み」 17
<script>タグの動的生成(Script-Inject) • Script-InjectはDOM構築をブロックしない = 非同期化 <!DOCTYPE html> <head> <meta charset="utf-8">
<script> (function() { var tag = document.createElement('script'); tag.src = 'time_5s.js'; document.head.appendChild(tag); })(); </script> <title>Script-Injectによる非同期化</title> </head> <body> <div>Script-InjectはDOM構築をブロックしない、この文章はすぐに表示される。</div> <div>「5秒後」にJavaScriptが実行される</div> </body> 18 5秒遅延
<script>タグの動的生成(Script-Inject) デモを見る ※ 4. Script-Injectによる<script>タグ生成 19
<script>タグの動的生成(Script-Inject) Script-InjectはDOM構築をブロックしない 素晴らしいように思えます が、大きなデメリットが2つあります 20
CSS/CSSOMとレンダリングブロック • <head>で読み込んだCSSは CSSOM(CSS Object Model)が構築されるまで レンダリング(=画面表示)をブロックする • bold.cssは太字・アンダーライン付きにするだけ <!DOCTYPE
html> <head> <meta charset="utf-8"> <link href="bold_5s.css" rel="stylesheet"> <title>CSSOM構築によるレンダリングブロック</title> </head> <body> <div>この文章はCSSOM構築を待つため「5秒後」に表示される。</div> </body> 21 5秒遅延 body { font-weight: bold; text-decoration: underline; }
CSS/CSSOMとレンダリングブロック デモを見る ※ 5. CSSOM構築によるレンダリングのブロック 22
CSS/CSSOMとレンダリングブロック CSSOMの構築完了まで レンダリングはブロックされる ※<head>内で読み込んだ場合のみ CSSOMの構築は DOM構築をブロックしない (DOMContentLoadedはすぐに発火する) 23
画面表示に必要な2つの鍵 画面表示には2つの鍵が必要 DOM構築(都度表示可能) <head>内のCSSOMを完全に構築済み 24
<link>タグの動的生成(CSS-Inject) • CSS-Injectならレンダリングをブロックしない = 非同期化 <!DOCTYPE html> <head> <meta charset="utf-8">
<script> (function() { var tag = document.createElement('link'); tag.href = 'bold_5s.css'; tag.rel = 'stylesheet'; document.head.appendChild(tag); })(); </script> <title>CSS-Injectによるブロック解除</title> </head> <body> <div>この文章はすぐに表示される。</div> <div>「5秒後に」強調表示に変化する。</div> </body> 25 5秒遅延
<link>タグの動的生成(CSS-Inject) デモを見る ※ 8. CSS-InjectによるCSS読み込み 26
<link>タグの動的生成(CSS-Inject) CSS-Injectなら レンダリングをブロックしない Flash of Unstyled Content(FOUC)に注意 ※CSS未適用の画面が表示される現象 27
メディアクエリでレンダリングのブロックを解除 • <link media=print>でレンダリングブロックを解除 = 非同期化 <!DOCTYPE html> <head> <meta
charset="utf-8"> <link href="bold_5s.css" rel="stylesheet" media="print" onload="this.media='all'"> <title>CSSのメディアクエリによるブロック解除</title> </head> <body> <div>この文章はすぐに表示される。</div> <div>「5秒後」に強調表示に変化する。</div> </body> 28 5秒遅延 onloadでallに戻す
メディアクエリでレンダリングのブロックを解除 デモを見る ※ 9. メディアクエリをprintとしてCSS読み込み 29
メディアクエリでレンダリングのブロックを解除 <link media=print>なら レンダリングをブロックしない しかし、転送優先度が最低(Lowest)になってしまう 30 Lowest!!
CSSとJavaScriptの読み込み • CSSとJavaScriptを読み込み • CSSOMの構築はDOM構築をブロックしない <!DOCTYPE html> <head> <meta charset="utf-8">
<link href="bold_3s.css" rel="stylesheet"> <script src="time_5s.js"></script> <title>JavaScriptとCSS読み込み</title> </head> <body> <div>この文章は「5秒後」に表示される。</div> <div>JavaScriptも同じタイミング(5秒後)で実行される。</div> </body> 31 3秒遅延 5秒遅延
CSSとJavaScriptの読み込み デモを見る ※10. CSSとJavaScript読み込み 32
CSSとJavaScriptの読み込み CSSOM構築完了は3秒後。 しかし <script>で5秒間DOM構築が停止、 画面表示は5秒後まで待たされます。 33
CSS読み込みとScript-Inject • JavaScriptをScript-Injectで非同期化 <!DOCTYPE html> <head> <meta charset="utf-8"> <link href="bold_3s.css"
rel="stylesheet"> <script> (function() { var tag = document.createElement("script"); tag.src = 'time_5s.js'; document.head.appendChild(tag); })(); </script> <title>CSS読み込みとScript-Inject</title> </head> <body> <div>この文章は「3秒後」に表示される。</div> <div>JavaScriptは「8秒後」に実行される。</div> </body> 34 3秒遅延 5秒遅延
CSS読み込みとScript-Inject デモを見る ※ 11. CSS読み込みとScript-Inject 35
Script-Injectによる非同期化で 画面表示は3秒後に高速化 しかし Script-Injectの実行がCSSOM構築を待つので 3秒 + 5秒 = 8 秒後にJavaScriptが実行される
これがScript-Injectの問題点の1つです。 CSS読み込みとScript-Inject 36
CSS読み込みとScript-Inject JavaScriptの実行はCSSOMの構築を待つ (外部ファイル・インライン共に) 37
リソースのプリロード機能 ≠ rel=preload • JavaScriptを、通常 ⇒ Script-Injectの順に読み込み <!DOCTYPE html> <head>
<meta charset="utf-8"> <script src="time_5s.js?no=1"></script> <script> (function() { var tag = document.createElement("script"); tag.src = 'time_5s.js?no=2'; document.head.appendChild(tag); })(); </script> <title>通常⇒ScriptInjectで読み込み</title> </head> <body> <div>この文章は「5秒後」に表示されます。</div> <div>JavaScript(1つ目)は「5秒後」に実行されます。</div> <div>JavaScript(2つ目)は「10秒後」に実行されます。</div> </body> 38 5秒遅延 5秒遅延
リソースのプリロード機能 ≠ rel=preload デモを見る ※ 12. JavaScriptを通常読込⇒Script-Inject 39
リソースのプリロード機能 ≠ rel=preload • JavaScriptを、通常読み込み ⇒ 通常読み込み <!DOCTYPE html> <head>
<meta charset="utf-8"> <script src="time_5s.js?no=1"></script> <script src="time_5s.js?no=2"></script> <title>通常⇒ScriptInjectで読み込み</title> </head> <body> <div>この文章は「5秒後」に表示されます。</div> <div>JavaScript(1つ目)は「5秒後」に実行されます。</div> <div>JavaScript(2つ目)も「5秒後」に実行されます。</div> </body> 40 5秒遅延 5秒遅延
リソースのプリロード機能 ≠ rel=preload デモを見る ※ 13. JavaScriptを通常読込⇒通常読込 41
<script src=...>はDOM構築が停止中でも ブラウザのプリロード機能が先読みする。 Script-Injectはプリロード機能が効かない これが2つめの問題点です。 リソースのプリロード機能 ≠ rel=preload 42
• 元々は2008年頃にIE8で実装されたもの • ブラウザによって名称が異なる ◦ Lookahead Downloader (IE8) ◦ Pre-loader
◦ Preload Scanner (WebKit) • 同じ時期にIEは同時Download数を2個⇒6個へ ◦ 現在は同時DL数6個がデファクトとなった • <link rel=preload href=...>と使い分けが必須 ◦ 基本はプリロード機能に任せる ◦ 動的に読み込まれるものには rel=preload リソースのプリロード機能 ≠ rel=preload 43
<script>をasync属性で非同期化 • <script>にasync属性を付けると非同期化する <!DOCTYPE html> <head> <meta charset="utf-8"> <link href="bold_3s.css"
rel="stylesheet"> <script src="time_5s.js" async></script> <title>JavaScriptをasync指定</title> </head> <body> <div>この文章はCSSOM構築を待って「3秒後」に表示されます。</div> <div>JavaScriptは「5秒後(表示されてから2秒後)」に実行されます。</div> </body> 44 3秒遅延 5秒遅延 async指定
<script>をasync属性で非同期化 デモを見る ※ 14. JavaScriptをasync指定 45
<script async>はDOM構築をブロックしない Script-Injectによる非同期化の上位互換 さらにDOM構築停止時のプリロード対象になる ついでにCSSOM構築も待たない 良いことずくめ しかし インライン<script>は非同期化できない問題 <script>をasync属性で非同期化 46
インラインの<script>を非同期化 • async属性はインライン<script>に適用できない <!DOCTYPE html> <head> <meta charset="utf-8"> <link href="bold_3s.css"
rel="stylesheet"> <script> (function() { setTimeout( function(){document.body.style.color = 'red'}, 5000 ) })(); </script> <title>インライン<script>によるDOM構築ブロック</title> </head> <body> <div>この文章は「3秒後」に表示される。</div> <div>「8秒後(表示から5秒後)」に文字色が赤に変化する。</div> </body> 47 3秒遅延 5秒後にフォントを赤に変更
インラインの<script>を非同期化 デモを見る ※ 16. インライン<script>によるDOM構築ブロック 48
インラインのJavaScriptでもCSSOM構築を待つ 1. CSS読み込み ⇒ CSSOM構築待ち 2. インライン<script> この順で登場するとCSSOM構築が完了するまで JavaScript実行とDOM構築がブロックされる インラインの<script>を非同期化
49
インラインの<script>を非同期化 • srcにデータURLで指定することでasyncを有効化 • data:text/javascript, に続けてJavaScriptコードを エスケープした文字列を貼り付け • エスケープはJavaScriptならencodeURI() <!DOCTYPE
html> <head> <meta charset="utf-8"> <link href="bold_3s.css" rel="stylesheet"> <script async src="data:text/javascript,(function()%7BsetTimeout(function()%7Bdo⏎ cument.body.style.color='red'%7D,5000)%7D)()"></script> <title>インライン<script>の非同期化</title> </head> <body> <div>この文章は「3秒後」に表示される。</div> <div>「5秒後(表示から2秒後)」の文字色が赤に変化する。</div> </body> 50 3秒遅延 インラインJavaScriptを データURLに変換 ※実際には空白なしで1行
インラインの<script>を非同期化 デモを見る ※ 17. インライン<script>の非同期化 51
インライン<script>も遅延原因になる 実行にはCSSOMの完全な構築が必要 可能な限り非同期化しましょう もしくは CSS読み込み前に<script>を移動するだけでもOK インラインの<script>を非同期化 52
まとめ 53
まとめ • HTML転送 ≠ DOM構築 = 画面表示 • <script>はDOM構築をブロックする •
CSSOM構築完了までレンダリングをブロックする ※ただし<head>内で読み込んだCSSのみ • 画面表示は2つの鍵が必要 ◦ DOM構築(部分的な構築でもOK) ◦ <head>内のCSSOMを完全に構築済 • JavaScript実行はCSSOM構築を待つ • インラインJavaScriptでもCSSOM構築を待つ 54
最後に 55
56 https://www.raccoon.ne.jp/company/recruit/index.html
ご清聴ありがとうございました。 https://www.raccoon.ne.jp/company/recruit/index.html