Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
ブラウザの制約条件から考えるフロントエンドのリソース設計/Frontend Performan...
Search
forrep
September 26, 2019
Programming
910
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
160
Linux && Docker 研修/Linux && Docker training
forrep
28
5.9k
RAGにベクトルDBは必要ない!DBも不要で運用めちゃ楽な RAG Chatbot を作った話
forrep
38
18k
Google Analytics でサイト速度を計測する / Measure site speed with Google Analytics
forrep
2
460
最近コードレビューで指摘したこと
forrep
4
650
「プログラマーのためのCPU入門」は入り口として丁度よい!
forrep
54
38k
DevTools でパフォーマンスチューニング入門 / Introduction to Performance Tuning with DevTools
forrep
2
560
技術的負債に対する視力を得る / How to View Technical Debt
forrep
0
970
しくじり先生 - NFS+sqliteで苦労した話から学ぶ、問題解決の考え方 / problem-solving approach
forrep
1
1.4k
Other Decks in Programming
See All in Programming
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
130
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
200
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
3k
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
220
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
700
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
180
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
150
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
260
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
190
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
2.3k
一人だけ、Kiroが静止する日
hideg
0
120
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
180
Featured
See All Featured
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
330
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Designing Powerful Visuals for Engaging Learning
tmiket
1
570
Ruling the World: When Life Gets Gamed
codingconduct
0
340
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
870
[SF Ruby Conf 2025] Rails X
palkan
3
1.4k
Why Our Code Smells
bkeepers
PRO
340
58k
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
550
Writing Fast Ruby
sferik
630
63k
Deep Space Network (abreviated)
tonyrice
0
310
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
390
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