フロントエンドチューニングの箇条殴り書き

普段気をつけてるよリスト

"モバイルで、WebViewとブラウザのコンパチで、特にセオリー化されていないデザインモジュールのなか、装飾画像もふんだんに使うぞ系サービス開発" の文脈における、パフォーマンス確保のため気をつけてるよリスト。

よく、パフォーマンス「向上」とか「確保」とか申しますが、メンテナンスコストなどと天秤にかけて、「必要十分」のラインを狙うのが重要だと思う次第。

画像リソース

画像リソースを揃えるときのセオリ。圧縮率とか最適化とか細かいチューニングはあれど、大雑把に下記を守る。そしてImage Optim(or 相当の処理)。

  • JPEGはプログレッシブで画質60くらい(オレ目安)
  • PNGは差し支えない範囲で色数をきちんと削る
  • 50px未満のサムネイルは@2.0xなリソースにしない
  • 案外、Androidあわせの@1.5xや@1.0xでも大丈夫なことすらある
  • GIFアニメを入れるときは、AndroidアプリにWebView.pauseTimer()を入れておく(バックグラウンドで表示してるとスレッド動き続けて電池おいしいです)

ネットワーク

画像リソースに引き続くところで、ネットワークコストについて。Webアプリ/サイトならではのナマモノな要因が関わってくるため、いわゆるit dependsの権化。

  • ATF ( Above The Fold ) のリソースは、なるべく1つあたり4KB未満で構成する/したい/できない
  • 上記ATF、またはHTMLにCSS, JSなどを埋め込んだ状態で提供したい
  • CSS Spritesや、Data URI (CSS) の肥大化を忌避する(太りすぎるとロード完了まで複数のリソースがずっと出ないことになってしまう)
  • CSS Sprites は15〜30KB程度でまとまるように留める(オレ目安)
  • Data URIは1KB未満の画像ファイルにのみ適用する(オレ目安)
  • Data URIがやむを得ず肥大化したら分割したり、setTimeoutなどで挿入を遅延させる
  • CSS Spritesは、Compassなどのツール利用を前提に、肥大化したら分割する
  • ドメインシャーディングは、スタティックリソース(css, js, img, etc...)のサーバーが2つあれば十分(オレ目安)
  • 2つかそれ以上用意した場合も、適当な分散をするとキャッシュ効かないしムダっぽいので気をつける
  • ビジュアルがモジュール化されて使い回されるように調整する(ネットワークコストにとって重要)
  • Expiresとかgzipちゃんと入れろ、PageSpeed or WebPageTest見ろ

スクリプティング

スクリプト(JavaScript)に関しては、正直あまり処理が重いアプリを作っているのではないので薄め。しかも最後が精神論です。

  • DOMに対するアクセス回数は最小限に留める(Itemの連続appendなどは、invalidateでまとめる)
  • DOMイベントはDelegationでまとめる(BackboneのView.delegateEventと同じイメージ)
  • Developer ToolのTimelineをこまめにチェックしてメモリ周りで致命的な問題がない状態を保つ(多少は目を瞑れ)
  • ヘビーなループが想定されるスコープ内の処理に"気を遣う"(※1)
  • minifierの気持ちになって書く
  • browserの気持ちになって書く

1. 単に、関数コールを減らしたり、古来からのミクロな高速動作する(と言われている)コードにするようなjsPerf的アプローチが常に良いわけではない。Use forensics and detective work to solve JavaScript performance mysteries - HTML5 Rocksとかを読むと分かるが、JavaScriptエンジンの最適化を阻害しない、という考えのほうが重要になりつつある、と思う。

レンダリング・アニメーション

最初から地雷を知っておけばそれらを回避するだけです。例えば、display: boxとかは古い実装だとレイアウトコストが高めとかありますが乱暴な話、怪しいものは使わなければどうということはありません

以下、GPUアクセラレーションについては使うべきところで使われている前提で。

  • よくあるbox-shadow, border-radiusを忌避する(※2)
  • 特別な事情がない限り、画像や非同期読み込みコンテンツの幅・高さは、イニシャルで確保しておく
  • position: fixedは要件定義からNOという(どうしても必要なときは全力!!)
  • アニメーションを利用するときは、Composition Layer の生成状態を確認する
  • Stacking Context と衝突しているようなら、アニメーション適用クラスに z-index による持ち上げを追加して切り離す(※3)
  • -webkit-backface-visibilityなどのハードウェアアクセラレーションお呪いは広域にかけない(GPU処理への過転送によりレンダリングが悪化する)
  • iOS6 だけアニメーションが引っかかるときは、アニメーション要素をラップしていたり、かぶさっている要素にも-webkit-backface-visibilityなどおまじないをかける(※4)

2. Skia DebuggerにみるCSSプロパティの重み ::ハブろぐ
3. GPUアクセラレーションとposition: relativeによるレイヤー生成について ::ハブろぐ
4. iOS6 html hardware acceleration changes and how to fix them | indiegamr

まやかし

フロントエンド実装として工夫できる細かいインタラクションまわりのこと。

  • 通信に200-300ms(?)以上かかる場合は、何らかのローディング表示を出す
  • ページ遷移に伴う通信のローディングは、大きめに出しても良い
  • 投稿やもっと読む処理などのアクションに伴う通信のローディングは、アクションを行ったUIの上か周辺で控えめに出す(何のアクションを待機してるのか分かりやすい)
  • ローディングのビジュアルアニメーションがコスト重かったら、テキストのゆったりした明滅だけでも、プログレス感は出る
  • 選択可能なアイテムは、タップ時にハイライトをかける(ブラウザ標準でも良いし、スタイル付与でも良い)
  • タップハイライト時、リストアイテムは touchstart からハイライトを付けるまで待ち時間をいれる(touchstart即時だと過敏)
  • タップハイライト時、ボタンは touchend からハイライトを消すまで待ち時間を入れる(しっかり押した感が出る)
  • click時の300msといわれるディレイ(除Chrome)の発生は、FastClickなどの実装で何とかする。全域適用よりは、ミッションクリティカルなUIだけでも良い。
  • ATFより下の細かい画像リソースは、スクロール同期系の遅延ロードをしかける
  • 大きい画像リソースは、スクロール同期だと「まだ読み込まれてないの?」と思われがちなので要相談
  • 画面遷移時のトランジションはターゲットデバイスで無理がないならやっても良いが、大概コストに見合わない感
  • Ajaxで「もっと見る」したコンテンツの先で、"戻る"したときに「もっと見る」した後の状態をキープすべき
  • 厳密な整合性よりも、多少曖昧なラインでDOM or Model をキャッシュすることによる恩恵を優先すべき

おしまい

殴り箇条書きですが、参考になる所があればご自由にお持ち帰りください系のまとめでした。思いついたら足すかもしれない。

上記のアレコレは、現職のコンテキストに依存してるところもあるので、アレ。