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
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
130
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
440
最近コードレビューで指摘したこと
forrep
4
630
「プログラマーのためのCPU入門」は入り口として丁度よい!
forrep
54
38k
DevTools でパフォーマンスチューニング入門 / Introduction to Performance Tuning with DevTools
forrep
2
540
技術的負債に対する視力を得る / 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
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
460
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
840
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
150
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
14
6.8k
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
370
ランチタイムLT会3周年!ランチタイムLT会を3年間続けられたお話
y0hgi
1
140
『コードを書く以外の』エンジニアリング〜課金基盤移行プロジェクト推進のためのTips4選
yuriko1211
0
390
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
220
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.9k
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
0
100
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
260
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
200
Featured
See All Featured
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Evolving SEO for Evolving Search Engines
ryanjones
0
240
My Coaching Mixtape
mlcsv
0
170
Site-Speed That Sticks
csswizardry
13
1.3k
The Invisible Side of Design
smashingmag
301
52k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Context Engineering - Making Every Token Count
addyosmani
9
1k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.4k
Un-Boring Meetings
codingconduct
0
340
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