『Webフロントエンド ハイパフォーマンス チューニング』学習メモ

Ch1 Web performanceとは何か

  • performance: userの様々な振る舞いにWeb pageが応答する速さ
  • Web page内でのinteractionのperformanceの最適化を目指す

Ch2 browserのrenderingの仕組み

  • 対象とするrendering engine
    • history
    • WebKit系のrendering engineを見る
    • rendering engine: browserの内部で利用するHTMLの描画engine
      • HTML, 画像ファイル, CSS, JavaScriptなどの各種resourceを読み取って,画面上の実際のpixelとして描画
    • JavaScript engine
      • V8など
        • V8はNode.jsでも使われている
    • WebView: browserと異なり,Web pageの表示のみを行うcomponent
      • online contentsをapplication内で表示/application内のcontentsを再installすることなしにdynamic updateのため.
      • WKWebView > UIWebView
  • browserのrenderingの流れ
    • HTML, CSS, JavaScript, HTTPなどの周辺要素が相互に関連し合って進むため,複雑
    • 4つの工程からなるrenderingが始まって,最終的に描画されるまで: Frame
  • resourceの読み込み: Loading
    • browserが, URLからHTMLを読み込んで,そこからさらにrenderingに必要な付属するresourceを読み込んで解釈
    • resourceの取得のためのnetwork protocol
      • (表)
      • 内部的な手続き
          1. URLに含まれるhostnameの解決
          1. HTTPによる取得
          2. 2-1. TCP connectionの確立
          3. 2-2. (@HTTPS) TLS connectionの確立
          4. 2-3. HTTP requestの送信とHTTP responseの受信
      • IPについて
      • TCPについて
      • TLSについて
      • UDPについて
        • QUIC protocolなどで使われている
      • HTTPについて
      • DNSについて
    • 各resourceの読み込み
      • HTMLの読み込み
        • URLからHTTP request → HTTP responseとしてHTMLを取得
        • → 取得したHTMLを解釈し,DOM(Document Object Model) treeを構築
          • DOM: HTMLのDocumentを表現するObject.rendering engineが利用する木構造を持つ内部表現.
          • DOM treeへの変換過程で,画像やCSSなどのDocumentに紐づくresourceの取得や読み込みを行う
          • DOM tree: JavaScriptからアクセス〇 → DOM操作
          • process
          • img: 画像.link: CSS.script: JavaScript
      • CSSの読み込み
        • CSS: HTMLで記述されるDocumentの内容や構造に対して装飾を加える
        • 要素を指定するCSS selectorと,それらに適用するCSS propertyと値の組を宣言する
        • link: 外部CSS fileを宣言.style: HTML file内部に埋め込まれたCSSの読み込み.
        • rendering engineがparse → CSSOM(Object Model) treeに変換
        • CSSOM treeはrendering engineの内部表現だが,JavaScriptからaccess
  • JavaScript 実行 -Scripting
    • JavaScriptの実行: 最初にJavaScriptファイルを読み込んだとき + DOMイベントが発火しevent listenerが起動するとき
    • 字句解析と構文解析
    • compile
      • 抽象構文木 → 実行可能な形式
      • JIT compile型が多い ←→ 仮想マシン用コードへの変換
        • JIT compile型: その処理系が動作しているマシンのCPUが直接解釈できる機械語に変換
          • 実行時のperformance〇
          • multi platform対応difficult
          • compile時のoverhead大
        • JIT(Just In Time) ←→ AOT(Ahead Of Time)
    • 実行
      • JavaScript内では,DOM APIを通じてDOM treeを操作
      • 後続のRendering, Painting phaseやLoading phaseを引き起こす
  • Layout tree構築 -Rendering
    • Calculate Style + Layout
    • Calculate Style
      • すべてのDOM要素に対して,どのようなCSS propertyが当たるのか計算
      • CSSOM tree内をすべて参照して,CSS selectorのCSS ruleのマッチング
      • CSS rule のmatching
        • CSS selectorのmatching
          • ある要素の親要素や同じ階層の要素に条件をつけるCSS selectorがある
            • e.g. body > .container > .button
            • selectorを右から左に解釈してmatching
        • 適用されるCSS propertyの算出
          • DOM要素に適合する複数のCSS rule setを,詳細度でソートしてスタイルを計算する.
          • 詳細度は,CSS selectorにより決定.
            • p.41 表に,selectorと詳細度の対応がある
          • 詳細度が大きいほど優先.同じときは,後に宣言されたものが優先.
          • 要素のstyle属性に記述されたCSS ruleは,どのCSS rule setよりも優先
          • CSS propertyに付加する!importantはstyleよりさらに優先される
          • Specificity Calculatorで確認できる
    • Layout
      • 要素の大きさ,margin, padding, 位置,z軸の位置を計算
  • rendering結果の描画 -Painting
    • Paint
      • 内部の低レベルな2D graphic engine向けの命令の列(Display List)を,Layerごとに生成
      • browserによって,組み込むgraphic engineが異なる
      • bottleneckにはならない
    • Rasterize
      • 生成された命令から,pixel(bitmap)へと描画
      • overhead大きい
      • layerという単位で1枚ずつ描画
        • layer: overwrapして表示するcontentsがあるときに生成
        • 描画済みのlayerを再利用して,再renderingが素早く容易になる
    • Composite(複合,合成) Layers
      • pixelにしたlayerを合成して最終的なrendering結果を生成
      • 3Dの処理などはGPU.ほかはCPU.
  • 再rendering
    • DOM eventにより発生
    • JavaScriptのコードにより,どのphaseを引き起こすか知ることがimportant

Ch3 tuningの基礎

  • 闇雲なtuningの害
    • trade off: developerの時間的resource.コードの単純さ.
    • best practice
      • HTTP requestを減らす
      • CDNを使う
      • Expires headerを設定する
      • componentをgzipする
      • style sheetは先頭に置く
      • scriptは最後に置く
      • CSS expressionの使用を控える
      • JavaScriptCSSは外部ファイル化する
      • DNS lookupを減らす
      • JavaScriptを最小化する
      • redirectを避ける
      • scriptを重複させない
      • ETagの設定を変更する
      • Ajaxをcache可能にする
  • ×推測,〇計測
    • bottleneckの解消がimportant
  • 目指すべき指標を設定する
    • performance metrics: RAIL
      • user中心のperformance model
      • Web page以外にも,複雑なinteractionやanimationを含むWeb applicationやHybrid applicationにも適用できる
      • Response, Animation, Idle, Load
      • Response: 100 ms
        • userが感じられる視覚的な変化
        • over 100 msなら,処理中を意味するindicatorの表示が〇
        • 指のtouchやscrollはAnimationと同じく16 ms以内が必要
      • Animation: 16 ms
        • 連続して行われるframeの中で1 frameの処理時間の目安
        • frame: Scripting, Rendering, Painting
        • 16 ms → 60 FPS(Frames Per Second)を満たす
        • frame中のJavaScriptの処理時間は6 ms以内
      • Idle: 50 ms
        • Idle状態で実行されるJavaScriptの処理時間
      • Load: 1000 ms
        • 1000 ms以内にsplash screenを表示して,そのほかのresourceの読み込みは遅延でも〇
        • cacheやloading 画面の表示で,各種resourceの読み込みを遅らせるのが〇
  • 計測手段
    • Chrome DevToolsなどdeveloper toolによる計測
      • Web page内の細かな計測や解析を行うのに有効
      • Web pageがどのように処理されてRenderingに至るのかを詳細・多角的にみられる
      • performanceのbottleneckの原因箇所の調査に有効
      • 継続的かつ定量的な計測には向かない
    • JavaScriptによる計測
      • performanceのmetricsの収集・算出の自動化
      • userの環境にばらつきがあるcaseで特に有効
    • performance診断tool
      • performanceが適切かどうか,performance改善のためのtechniqueをadvice
    • 継続的監視
      • 改修を重ねていくときにperformanceの問題を常に確認する必要がある
  • Chrome DevToolsなどdeveloper toolによる計測
    • AndroidでのChrome DevToolsの利用方法
      • PCとAndroidをUSBで接続する
    • WebViewを使う場合
      • minimum code for Android application内でWebViewを呼び出しつつChrome DevToolsを利用するactivity
    • iOSでのWeb inspectorの利用
    • Chrome DevToolsの主要機能
    • Network panel
      • networkを通じたresource取得のtimelineを細かく見る
      • blue line: DOMContentLoaded
        • 遅い場合はscriptによる読み込みブロックなどの問題
      • red line: Load event
        • 遅い場合はresourceの容量が過大
      • 回線状況の再現も〇
      • 個別のresourceの取得時間: timeline上の表示にカーソルを合わせる
      • Connection SetupやRequest/Responseの内容
        • Waiting(TTFB)が長いときは,サーバ処理に時間がかかっている
    • Performance panel
      • page loadや操作に関するすべてのeventを分析〇
      • frame chart
        • blue/red lineはNetworkと同じ
        • green line: 最初のPaintが発生するtiming(page上になんらかの表示が反映されるtiming)
        • 特に時間のかかっている処理の割り出しに使う
      • profileの取得: Performance panelの記録
        • Rendering engine内のほとんどすべてのphaseのprofileを細かくとることができる
    • Memory panel
      • memory leakの検知やmemoryの使い過ぎの把握のため
      • heap snapshot, memory割り当ての確認ができる
  • JavaScriptによる計測
    • Navigation Timing APIによる計測
      • browserのnavigation時の詳細なperformance情報を取得できる
      • browserの各段階の処理時間を計測〇
      • 以前のWeb pageのunloadの時間など,Web serverでは検知できない情報を得られる
      • Objectのpropertyの差を求め,処理時間を算出
      • timing Objectは参照するtimingに注意
      • navigation Objectの内容も合わせて見る
        • どのようなnavigationか
    • User Timing APIによる計測
      • 任意の処理にかかる時間を計測〇
        • interactionなど必ずしも計測地点を機械的に宣言できない処理の計測
      • performance
        • mark()
        • measure()
        • getEntriesByName()
    • Resource Timing APIによる計測
      • 個別のresourceの取得にかかっている時間の統計情報を取得
        • redirectにかかる時間
        • DNS lookupにかかる時間
        • network connectionの確立にかかる時間
        • HTTP responseを受け取るのにかかる時間
      • Network panelとほとんど同じものが対象
      • PerformanceResourceTiming Object
    • Performance Observerによる監視
      • これから起こる処理のperformance informationを指定して監視
      • 柔軟にperformance informationを取得
        • SPAなどinteractionを多く持つようなWeb pageでのperformanceも容易に取得〇
        • 記録・解析のためにreal timeでserverに送信も〇
      • modern browserの中では,Google Chromeのみ対応
    • 高精度なtimestampを得る
      • performance.now()とDate.now()の違い
        • performance.now()は高い信頼性と精度
        • performance.timing.navigationStartからの経過時間を返す
        • 浮動小数点 ←→ 整数
          • FPSの算出など高い精度が必要な計算や,animationの同期処理を行う場合などで有効
  • performance diagnostics tools
    • performanceの改善のための助言ができるtool, service
    • 詳細は分からないが,best practiceとの乖離が分かる
    • Audits @ Chrome DevTools
      • 数clickだけの操作で手軽に行える
    • PageSpeed Insights
      • onlineでURLを入力
    • Lighthouse
      • PageSpeed Insightsと近い用途だが,CLI toolの提供や結果のexportの容易さなど,定期的な実行により適している部分がある
      • PWAへの準拠度や,accessibility対応の計測も〇
  • performanceの継続的監視
    • New Relic Browser

Ch4 resource読み込みのtuning

  • resource読み込みの流れ
    • HTML fileから始まるresourceのgraphを構築しつつ,network protocolを通じてresourceを取得・parse
    • TCP/IP + HTTP/1.1で考える
  • HTML/CSS/JavaScriptを最小化する
    • 余計なbyte列を除去する各tools
      • deploy前で自動化する
    • JavaScript libraryは最小化されているものを使っても〇
  • proper image typeを選択
    • 写真: JPEG, simple animation: GIF, others: PNG
  • image fileを最適化
    • 各toolsを,wrapper tool, task runnerやbuild toolなどから使うことも多い
  • Web fontも最適化可能
  • CSSのimportを回避
    • HTTP requestを減らすという原則 + 直列な取得・読み込みを避けるため
    • toolやメタ言語で結合する
  • JavaScriptのsyncな読み込みを避ける
    • JavaScriptのdocument.write()はDOM treeの構築に影響を与えるため,script要素はdocumentのparseやCSS fileの読み込みをブロックする
  • JavaScriptをasyncに読み込む
    • defer attribute
      • JavaScript fileは,DOM treeが構築されてから初めて実行
        • DOMContentLoaded eventの発火前に実行
      • 実行順を保証
    • async attribute
      • JavaScriptのdownload時点で実行される
      • 実行順を保証しない
        • 依存関係は,ファイルの結合などで解消が必要
    • JavaScriptでscript要素をasyncに読み込む
      • 読み込むtimingを細かく制御したい場合など
    • async 読み込みの利用方針
      • asyncが一番performance〇
      • asyncがダメならdefer
      • deferもダメなら通常のscript要素
  • device pixel比ごとに読み込む画像を切り替える
    • srcset
    • さらにresponsive対応をするなら,pictureやsizes
  • CSSのmedia queryを適切に指定する
    • FOUC(Flash Of Unstyled Content)の回避のため,renderingの前にCSSの取得と読み込みを待つようになっている
    • link要素のmedia属性を適切に指定することで,screen以外のCSS fileの読み込みがrenderingをブロックしないようになる
      • CSS内でmedia属性を指定することよりよい
  • CSS spriteを使って複数の画像をまとめる
    • HTTP requestを減らす
    • まとめた画像の一部を切り取って表示
  • CriticalCSSで最初の描画を最適化
    • CSSをinline化
    • 最初の描画に必要なCSSをstyle要素に書き出す
    • CriticalCSS以外のtoolもある
    • ほかの最適化techniqueではperformanceが不十分なときに検討
  • resourceを事前読み込みしておく
    • DNS pre fetch(dns-prefetch)
      • 対象のpageをホストしているドメインには意味ない
    • resourceの事前読み込み
      • link rel="prefetch"
    • Web pageのpre rendering
      • link rel="prerender"
      • landing pageやpage送りのnavigationがあるときなど,遷移先が限られているときに〇
    • connectionの投機的開始
      • link rel="preconnect"
    • 事前読み込みするresourceの動的追加
      • 事前読み込みのtimingを制御
  • Gzip圧縮を有効にする
    • HTTP response内のContent-Encoding: gzip
    • Apacheでの圧縮の指定方法
    • 画像や動画など圧縮済みのものは回避要
    • HTTP response headerをdeveloper toolで見ることで圧縮の確認ができる
  • CDNを用いてresourceを配信する
  • domain sharding
    • 多くのmodern browserでは,hostごとの同時connection数の上限は6
    • CDNなどでresourceを配信するhostを複数用意
    • DNSの名前解決にかかる時間は増える
    • HTTP/2ではあまり意味がない
      • 1つのconnectionで並列にrequest/response
  • not redirect
    • directoryの名前で終わらず,/をつけるかファイル名を明示する
      • directoryの名前で終わると,/をつけたURLにredirectされる
  • browserのcacheを活用
    • Expires header
      • 強いcache
      • Apacheでの指定方法
      • HTTP response headerを確認するとわかる
      • server/clientで時間設定がずれていると×
    • Cache-Control header
      • 強いcache
      • max-age
      • Apacheでの指定方法
    • Expires/Cache-Control headerの使い分け
      • Cache-Control headerが優先される
      • Expires headerは古い
    • URLにtokenを付加する
      • 強いcacheを疑似的に消す
      • PHPなどのserver sideで付加することがほとんど
    • 弱いcacheの活用
      • 条件つきHTTP requestを使う
    • Last-Modified headerの設定
    • ETag headerの設定
      • Entity Tag(version)で表現
    • Last-Modified/ETag headerの使い分け
      • ETagが優先される
      • Apacheでの指定方法
      • 複数台のWeb serverのときは,ETagが変わってしまうため対応が必要
        • ETagの柔軟性が不要なら,ETagを付加せずLast-Modifiedのみ指定
    • cacheの使い分け
      • 静的なresourceは強いcache
      • まず強いcacheを使えないか判断し,だめなら弱いcache
  • Service Workerの使用
    • JavaScriptからcacheの制御を柔軟に実行可能
    • Web Workerの一種で,main threadとは別threadで動作
    • Web pageとWeb server間でproxyのように動作し,resourceをcacheから取得するかWeb serverから取得するか決定
    • Service Workerの導入
      • https or localhostのみ〇
      • code例
      • offlineに対応したWeb applicationの開発もできる
      • cacheの制御やresourceの取得も柔軟にcustomize〇
      • cacheでresourceのload時間を短くしたい場合にも有効
      • 対応browserは限定的なので,HTTP headerによるcacheをまず適用したうえで実施する
    • 廃止されるApplication Cacheの代替になる
  • HTTP/2の利用
    • SPDY protocolがbase
      • SPDY protocol: resource読み込みのlatencyの削減を目的にGoogleが開発
    • binary化したprotocol
      • HTTP/1.1: text baseの通信
      • 効率〇
    • HTTP/1.1のsemanticsの再利用
      • HTTP/1.1とTCPの間に挟まって通信を効率化するような形
    • requestとresponseの多重化
      • browserの同時connection数のlimitなし
    • HTTP headerの圧縮(HPACK)
      • RFC7541
      • 以前送ったHTTP headerの差分のみをお互いに送る
        • 無駄が減る.requestごとの効率up
    • HTTP/2 protocolはTLSが事実上必須
      • 速度は問題ないケースもある
    • HTTP/2で無意味になるtechnique
      • HTTP request数を減らしたり,同時接続数の制限を疑似的に増やす必要がなくなる
    • HTTP/2 対応 reverse proxyの利用
      • clientからのaccessをHTTP/2 serverが処理し,実際のcontents配信はHTTP/1.1 serverが行う構成を取れる
  • QUIC protocol
    • UDP上のnetwork protocolで,QUIC protocolの上でHTTP/1.1やHTTP/2 protocolを使える
    • merit
      • connection開始時のlatencyの削減
        • tokenの使用による
      • Head-of-Line Blockingの削除
        • 再送を個別のpacket単位で行う
    • UDP上でありながら,TCPのpacket loss検出や誤り検出ができ,TLSの盗聴・改ざん防止もできる
    • 書籍が書かれた時点では,Google Chromeのみ対応
      • Googleのserviceでは使われている
  • build tool
    • ファイルの依存関係を解決し,複数のファイルをまとめる目的
    • task runnerも同等の用途で使われる
    • tuningのためのtechniqueの自動化に必要
    • TypeScriptやBabelのtranspileや,buildまでの経路の複雑化などから,build toolは不可欠になってきている

Ch5 JavaScript実行(Scripting)のtuning

  • HTML5になり,文書だけでなくapplicationを表現するplatformになった.
  • 文書と構造: HTML, CSS ←→ 動的な側面: JavaScript
  • JavaScriptの実行model
    • UI thread
      • tab1つにつき1つのUI thread(main thread)
      • JavaScriptの実行だけでなく,rendering engineの様々な処理が実行
        • Layoutの計算,rendering処理,DOM eventの発火など
    • event loopと実行queue
      • JavaScriptはevent loopというmodelで動作するため,single threadでの動作にもかかわらず,複数の処理を同時に実行できる
        • responseの受け取りなどの継続する処理は,asyncで動作するcallbackの受け渡しやevent listenerによる
        • networkなど処理待ちの時間は,タスクを一度終了しUI threadに制御を戻す.処理の再開時にはじめてUI thread上での処理が始まる.
        • 例外
  • JavaScriptのbottleneckを特定する
    • Performance panelによる計測
      • rendering engineの行うほとんどの処理のprofileを取れる
        • JavaScript, UI threadのrendering, DOM eventの処理など
        • JavaScriptでは,どの関数でどのくらい時間がかかっているか細かくわかる
      • performance diagnosticsなら,まずはPerformance panelでprofileを取る
    • 各処理の確認方法
      • 警告箇所と,ほかの処理の妨げになっているところや明らかに処理時間が長いものを見ていく
  • GCを避ける
    • requestAnimationFrame()などのときに,問題になる
    • 検知: Performance panelでprofileを取る
    • 防ぐ: 新しいObjectを生成しないか,必要なObjectや配列を予め生成しておく
  • memory leakを防ぐ
    • importance
      • performanceやapplicationの安定性のためにimportant
      • desktopでもswapで遅くなるし,mobileではapplicationがcrashする
    • detection
      • Performance panelでprofileを取る
    • heapの3点観測
      • heap snapshotを3つとる
      • Summary viewの見方
        • 黄色のObject: JavaScriptから参照されているObject
        • 赤: documentのDOM treeから分離したDOM treeに含まれているDOM要素
    • console.log()によるmemory leak
      • log()以外も,consoleに値を解析して表示する類のものは,特殊な参照がつく
      • debug処理の除去の自動化ができる
    • DOM leak
      • DOM tree自体もleakする
    • DOM leakの検知
      • memory leakの検知と同じ
      • 不要になったDOM要素はGCで初めて回収される → profileを取り終える前に,Performance panelの左上のゴミ箱マークで,GCを発動させて不要なDOM要素の解放が必要.
  • WeakMap, WeakSet
    • weak reference: GCでは利用されていると見られない
    • WeakMap: あるObjectの拡張や,private memberを持ちたいときに使える
    • WeakSet: あるObjectにflagを立てたいときに使える
    • 利用して〇なら最初から利用する
  • Web Workersの利用
    • codeの複雑化,thread生成costなどのtrade offあり
    • 利用方法
      • Web WorkersのthreadとUI thread間の通信: message passing(asyncにデータを通信し合う
        • postMessage(), event listener
        • 共有ではなくcopy
    • multi Web Workersを生成する
      • multi coreで並列計算
      • navigator.hardwareConcurrencyを参照してコア数を取り,それに応じたWeb Workersを生成する
        • 論理的なコア数が見える
    • Transferableを利用
      • copyとcopyのoverheadを回避
      • 所有権が移動する
      • Transferableを実装しているObject
        • ArrayBuffer: 型つき配列のdata storage
        • MessagePort: ほかのdocumentとの通信のために使う
    • 制限
      • 使えないObject
        • DOM要素,document Object, window Object, parent Object
      • → 純粋なデータ処理のみをWeb Workerで行う
  • asm.jsによるJavaScript高速化
    • 高速実行のためのJavaScriptのsubset language
    • specification
      • 計算はすべてstatic typing
      • 計算で使える型はint, double, floatのみ
      • asm.js module内部では仮想的にGCが利用不可
    • asm.js形式のコードを書きだすtranspilerによって処理を記述する想定
    • いずれWebAssemblyにreplaced
  • WebAssembly
    • より高速なloadと実行を目的として各browser vendorによって策定されている,browser上で実行可能なbinary format
    • JavaScriptの一部の機能を代替
    • merit, compared to asm.js
      • load time短縮
      • parseの簡略化
      • heap sizeの制限緩和
      • memoryに対する柔軟な読み書き
  • SIMD.jsの利用
    • SIMDJavaScriptから扱えるAPI
    • SIMD: Single Instruction Multiple Data
      • 複数の値の計算を一度に行う
      • data levelでの並列計算
      • x86ではSSE(Streamed SIMD Extensions), ARMではNEONという命令セットがある
        • SIMD.jsのAPIは,内部でこれらの命令を使う
    • 利用方法
    • 算術演算の一覧
    • 高速化の目安
      • 4つを一度に計算しても2~3倍程度
    • 標準化と対応browser
      • WebAssemblyに置き換えられていき,正式な仕様にはならない見通し
  • 高頻度で発火するeventの抑制
    • scroll, resize, touchmoveなど
    • setTimeout()やrequestAnimationFrame()で,ある一定の頻度でのみ実際の処理を行うようにする
    • そのほか,視差効果やscroll event listenerなど
  • mobile端末でのclick eventの遅延をなくす
    • meta要素によるviewportを適切に設定する
    • FastClickやTappy libraryを使っても〇
  • Passive Event Listenerでscrollのperformanceを改善する
    • event.preventDefault()が無効になることを保証
    • capture phaseでevent listenerを呼び出し
    • browserでのsupportの確認処理
    • scroll performanceの改善以外にも,event listenerがinteractionをブロックする時間が気になるときには検討〇
  • setImmediate()のasync 実行
    • setTimeout()は,指定した時間の後にasync実行
      • ↑ ずれがある
    • ←→ setImmediate()は,UI threadがidleになったらすぐに実行
    • clearImmediate()で解除
    • polyfill libraryのsetImmediate.jsで使える
  • idle時処理を使う
    • requestIdleCallback()
    • cancelIdleCallback()で解除
  • page表示状態を確認する
    • 状態に応じて,animationのon/offなどを行う
    • 正確なpage viewの測定にも使う
    • Page Visibility API
      • document.hiddenを参照
      • visibilitychange event
      • document.visibilityState
  • 無駄なForced Synchronous Layoutを減らす
    • DOM操作→関連するDOM要素のLayout情報を参照で,Forced Synchronous Layoutが引き起こされる
      • Recalculate StyleとLayoutがsyncに処理される
      • JavaScriptともsyncに実行
    • Layoutに影響する操作
      • style attributeやstyle propertyを通じて要素の大きさや座標にかかわる操作をする
      • DOM要素のclass属性を変えて,当たるstyleを変更して要素の大きさや座標を変更する
      • DOM treeの構造に変更を加える操作(DOM要素の追加・削除など)
    • 計測
    • Layout Thrashingを避ける
      • loop中でFSLを繰り返し起こしてしまうこと
    • FSLを防ぐ
      • DOM 操作の前にLayout情報を参照する
      • requestAnimationFrame()で計算済みのLayout情報を参照する
  • DocumentFragmentの追加
    • Web pageのdocumentの断片を表す
    • DOM treeへのDOM要素の追加を速くできる
    • 複数のDOM要素を格納〇
  • Intersection Observerで効率的に交差を検知する
    • あるDOM要素と親要素が視覚的に交差しているか監視
    • 使い方
    • not supportedなら,scroll eventで処理したりしないといけない.問題がある.
  • canvas要素の2D Context animation
    • 特徴
      • requestAnimationFrame()やsetTimeout()で一定時間ごとにcanvas要素の再描画が必要
    • sub pixelを避ける
      • あらかじめ整数値に変換しておく
    • 描画結果のcache
      • prerenderingとも呼ぶ
    • canvas要素をlayerとして使う
      • 必要な前景layerでのみ描画
  • requestAnimationFrame()を活用する
    • setTimeout()やsetInterval()の課題
      • proper timingでcallbackの呼び出しがdifficult
    • requestAnimationFrame()によるanimation
      • 自動的に呼び出しtimingを最適化
      • 指定したcallbackを,browserのrenderingの処理に合わせて,proper timingで呼び出し
  • JavaScriptからCSS Transitionを使う
    • animationの進行中はJavaScriptのコードは一切実行されない
      • requestAnimationFrame()とは異なり,JavaScriptがbottleneckにはならない
    • UI threadとは別のthreadで実行
    • rendering engine内部で最適なtimingで実行される
  • WebGL
    • GPUを用いた高速なgraphic処理のためのcross platformなAPIであるOpenGLのうちの,OpenGL ES2.0をbrowser上から利用するためのAPI
    • library
  • WebCL
    • GPUによる超並列計算ができるOpenCLをbrowser上から利用できるAPI
    • not supportedで,一般的な使用は×
  • 小さな最適化
    • 有意味でないことが多い
    • まずはbottleneckの解析
    • 次は,アルゴリズム・データ構造や基礎技術の改善

Ch6 Layout tree構築(Rendering)のtuning

  • Rendering: Calculate Style + Layout
  • interactionの高速化にもつながる
  • Layout tree構築の流れ
    • CSSのmatching処理
      • CSS rule set: CSS selector + CSS property
      • CSS selectorは右から左に向けて処理
      • selectorの記述が増えるほど,試行回数が増えて時間がかかる
    • DOM要素の位置情報を計算する
      • rendering対象内での絶対位置
    • Rerendering
      • 内部表現の再利用,不要な処理のskip
      • Recalculate Style
      • 操作とRerendering時に起こる処理との対応を知る
  • Layout tree構築におけるperformanceの計測
    • Performance panel
      • Recalculate Style
        • Elements Affected
      • Layout
        • Nodes that need layout
        • Layout root
  • 高速なCSS selectorの記述
    • DOM treeにも注意が必要
    • CSS selectorをsimpleにする
      • 試行回数の改善に加えて,CSS rule setの詳細度が一定になることで,保守性も上がる
    • 子孫selector, 間接selectorを避ける
    • 全称selectorとの組み合わせを避ける
      • そもそも全称selectorを避けた方が無難
  • BEMを用いる
    • 設計・保守しやすさを上げる + performance〇
    • BEM: Block, Element, Modifier
      • Block: page内を構成するひとかたまり.header, footer, 記事など.
      • Element: Blockを構成する要素
      • Modifier: BlockやElementの見た目や振る舞いを拡張
      • 1つのclass selectorのみでCSS selectorを宣言する
  • CSS selectorのmatching処理を避ける
    • DOM要素のstyle propertyを直接変更すると,matching処理を回避できる
      • 必ずそうするべきというわけではなく,高速なperformanceが必要なanimationやinteractionのときのみ
    • 利用していないCSS rule setを減らす
      • UNCSS
        • build toolとの組み合わせも〇
    • media queryを指定する
      • 不要なrule setをまとめて除外できて〇
  • Layoutを高速化する
    • a.c.a Reflow
  • Layoutを避ける
    • Layoutの原因
      • DOM要素の座標や大きさの変化
      • DOM treeの構造の変化
      • DOM要素のcontentの変化
    • Layoutの範囲を限定する
      • いずれかの条件
        • svg要素
        • type="text", or type="search"のinput要素
        • table要素の子孫じゃなくてかついろいろ条件を満たす
  • DOM treeから切り離して処理する
    • DOM treeから離れれば,Renderingはなくなる
    • remove()
    • 必要になった時にappendChild()などで再挿入すればよい
  • Layoutを減らす非表示
    • display: none
  • img要素のsizeを固定
    • height, widthを指定しないと仮の大きさで1度Layoutが走る

Ch7 Rendering結果の描画(Painting)のtuning

  • interactionやanimationを実装するときに頻繁に実行される
  • Rendering結果の描画の流れ
    • → Ch2
  • 再描画(Repaint)
    • 原因
      • Layoutが引き起こされる
      • 描画が引き起こされる
        • Paintingに直接関係するCSS propertyを変更したとき
        • 確認: Chrome DevToolsのRendering option内の,Paint Flashing
      • Layerの合成が引き起こされる
        • opacity, transform CSS propertyが変更されたとき
          • 高速なanimationを実装するためには,これらのみの変更とするのが〇
        • cost小さい
  • CSS propertyの変更が何を引き起こすか
  • Layerの生成条件
    • Layer treeが構成される
    • GPUに転送されるGraphics Layerが,performanceに影響大きい
      • うまく扱うと,animationを高速化できる
    • Layer treeを確認する
      • Performance panel
      • Layer treeの詳細を確認
        • 歯車 → Enable advanced paint instrumentation(slow)にチェック → profileを取得 → Frames → Layers
      • Layerの範囲を確認
        • Rendering optionのLayers Borders
  • 描画のoverheadを解析
    • Performance panelでPaint Profilerを見る
    • Paint Profilerの確認方法
  • GPUによって合成されるlayer
    • transformCSS propertyに3D変形を指定したとき
      • GPUのVRAMに転送→Composite Layers処理があって初めて3Dになる
        • transform propertyが変更されてもPaintは起こらずComposite Layersのみ起こる.
        • Composite Layers内のGPUでの変換のみの処理は,Rerenderingの中で最速
  • translateZ hack
    • translateZ(0)により,結果を変えずにGPUで合成できる
    • position: fixedのscroll speedの改善
    • body要素にtranslateZ hackを用いる問題
      • translateZを使うためのrule
        • Rasterizeされることが少ない要素に用いる
        • 領域がそれほど大きくない要素に用いる
        • 必要なときだけ用いる
    • 必要なtimingだけtranslateZ hackを用いる
      • JavaScriptでDOM要素のstyle propertyを指定する
    • will-changeCSS propertyによるtranslateZ hackの代替

Ch8 高度なtuning

  • 大量のDOM要素を扱うvirtual rendering
    • virtual rendering(virtual list): 実際にuserに見える箇所でのみ,表示する要素をDOM treeに動的に挿入
    • concept
    • algorithm
      • scroll領域の確保
      • contentsの読み込み
        • 表示する要素は絶対座標を計算して追加
      • scrollの検知
        • 不要な要素はunload
    • 事例とlibrary
  • なめらかなanimation
    • 指標と基本的な考え方
      • RAILを使う
      • Rerenderingのphaseを減らす
    • skip Calculate Style
      • JavaScriptでDOM要素のstyle propertyを直接変更
      • 不要ならDOM treeの構造やDOM属性を変更しない
    • skip Layout
      • transformCSS propertyの値に,translate()やscale()を使う
    • skip Paint
      • Paintを引き起こさないproperty
        • opacity
        • transform
      • これらを使えない場合は仕方ない
    • layerの合成の最適化
      • translateZ hack
  • will-changeCSS propertyによる最適化
    • CSS property名を指定
      • opacity, transformのみ
    • scroll-positionを指定
      • 要素の移動(animation)や素早いscrollに対応
    • contentsを指定
      • animationや変更を予想
      • cacheの生成・維持を省ける
    • dynamicに利用
      • JavaScriptからのdynamicな利用が〇
      • CSSでの宣言は,その要素が常に変更されるときのみ
    • 使い方
      • 最適化においては,見かけほど有用ではない
  • CSS ContainmentでRerenderingを最適化
    • CSS Containment: DOM treeの一部に封じ込め〇
    • 利用方法
    • layout: Layoutの封じ込め
      • 副作用: floatCSS propertyでの回り込みの影響がなくなる
    • paint: Paintの封じ込め
      • Layoutの封じ込めとともに,大きな最適化
      • 副作用3点
    • style: styleの封じ込め
      • 単体では使わない
    • size: 大きさの封じ込め
      • 単体では使わない
      • layoutと併用したり,content/strictを指定して使う
    • content/strict: 複数の封じ込め
      • content: layout + paint + style
      • strict: layout + paint + size + style
        • 最も最適化の効果〇
        • まずはstrictで,だめならcontent
  • AMP(Accelarated Mobile Pages)
    • static contentsを高速に提供
    • 専用CDNやprerenderingなどで〇

Ch9 認知的tuning

  • indicatorを使う
    • 1sを超える処理や読み込みのとき
    • 10sを超えるときはprogress barなどの進捗の表示が必要
  • interface previewを使う
    • indicatorより印象〇
  • 処理が終わったように振る舞う
    • beforeunloadで処理中の離脱へのアラート
  • 無限scroll
    • 同様の要素を表示するpageで使う
    • userのscrollをJavaScriptで検知,pageの最下部になると,次のpageの情報を読み取って動的に読み込むべきcontentsを画面下部に追加
    • 一部のRerenderingで済むため速い
    • 実装上の注意
      • → 5.11
    • virtual renderingとの違い
      • 無限scrollはvirtual renderingと併用する
    • merit
      • waiting time小さい
    • demerit
      • footer使えない
      • back buttonで表示が壊れることがある
        • リンクは別windowにするなど対応が必要
  • 投機的なresourceの先読み
    • user activityの洞察と解析が必要
    • 事例
    • 手段
      • JavaScriptで実装したapplication levelのcacheを使う
      • IndexedDB, LocalStorageなどのstorageで保存するか,もしくは単にJavaScriptの変数で保持(SPAなどのとき)
      • Resource Hints API(4.11)も〇
    • SPA: Single Page Application
      • SPA以外は,page操作で断絶 → userの体感速度を大きく低下
      • Ajaxの発展形
      • library, frameworkが必要
        • React.js, Angular, Vue.jsなど

Appendix SVGのperformance特性

  • SVG: Scalable Vector Graphics
    • XMLで表現されるVector Graphicsのformat
    • browserで利用できる唯一のVector Graphics format
    • HTMLと親和性がある
      • img要素ではなく,svg要素で,その画像をdocument内に直接埋め込める
        • tagの記述も〇
        • JavaScriptでの振る舞いを追加したり,CSSで修飾もできる
    • JavaScriptSVG内の視覚的要素をanimationさせたり,event listenerを追加してinteractionを与えられる
    • HTMLのanimationの問題もいくつか回避している
    • JavaScriptでanimationを行う
      • 属性を操作
        • LayoutはSVG要素内に限定してくれる → 通常のDOM要素のanimationよりもperformanceの負荷小さい
      • CSS Transitionを使う
        • 通常のDOM要素のtransformCSS propertyの変化とは異なり,LayoutからRerendering
    • SMILによるanimation
      • SMIL: Synchronized Multimedia Integration Language
      • SVG animationは,SMILのanimationの要素を利用
      • SVG animationは,Web標準から外れる予定