Google のモバイルに関するスピード向上のためのガイドラインである Mobile Analysis in PageSpeed Insights の一部を適当に訳したので公開する。これは個人的なもので内容の正確性とかは一切保証しないので注意してくれ。


PageSpeed Insights によるモバイル分析

PageSpeed Insights では、モバイルネットワークという劣悪な環境においてページを1秒以下で読み込むにはどうすればよいか、Google の推奨事項に基いて改善点を分析することができる。分析によれば、ページの読み込みに1秒以上かかってしまうと、ユーザの思考の流れは一旦絶たれてしまうという。これでは快適なネットサーフィンとは到底言えない。重要なのは、ユーザーがまだページに興味を抱いている間に、どんなネットワーク上でも最善の体験を提供すること、これだ。

もちろん、1秒以下というのは簡単なことではない。しかし朗報だ。ページのすべてを1秒以内に表示しなければならない、というわけではないのだ。その代わりに、Above-the-fold (ATF) と我々が呼ぶ、画面に最初に表示され、ユーザーの視野に最初に入ってくる部分を1秒で表示すればいい。あとは、ユーザーがそれを読んでいる間に、他の部分をレンダリングしてしまえば良いのである。

モバイルネットワークは遅い

どんなネットワークにも1秒以下で対応する、というのは並大抵のことじゃない。4G や 3G、あるいは 2G のどんなネットワークからもユーザはやってきうる。もちろんだがモバイルは遅い。はるかに遅い。我々は ATF コンテンツを1秒、つまり 1000 ms で表示したいのに、ネットワークのせいでかなりの時間を食ってしまう。一回ののラウンドトリップに、これだけの時間がかかってしまうのだ。

  • 3G なら 200-300 ms
  • 4G なら 50-100 ms

今のところ世界で一番メジャーなのは 3G だ。たしかに 4G も徐々に導入が進んできてはいるが、平均的なユーザーは 3G を利用していると考えるべきだろう。つまり、リクエスト1回につき、平均で 200 ms、0.2 秒かかると見積もるのだ。

そう考えると、DNS ルックアップで 200 ms、TCP ハンドシェイクのためのラウンドトリップでもう 200ms、そして実際の HTTP リクエストとレスポンスで 200ms かかるわけだ。もう 600 ms = 0.6 秒も経過してしまった。あと 400 ms しか残っていないではないか!

それでも1秒未満を達成するのだ

あとたった 400 ms でどうしろっていうんだ?サーバー側でレスポンスを生成し、クライアントサイドのコードを実行し、ブラウザーでコンテンツのレイアウトとレンダリングを行わなくてはならない。我々の野望は潰えたのか?いや、そうではない。こうすればいい:

  1. 200 ms 以下でレスポンスを返す: サーバーが最初の HTML を返すまでの時間からネットワークの転送時間を引いたものがサーバーレスポンスタイムだ。我々には時間がないので、これはできるだけ小さくしよう – 200 ms 以下が理想だ。

  2. リダイレクトの数の最小化: ひとつ HTTP リダイレクトを入れるたびに、ラウンドトリップをひとつかふたつふやすことになる(DNS ルックアップが必要ならふたつだ)。すでに見たように 3G 回線ではこれは致命的だ。その時点で数百 ms のハンデである。リダイレクトはできるだけ排除しよう─無くせるなら無くした方がいい。特に HTML 文書に関しては特に重要だ (“m.” とか “touch.” とかはクールじゃない)。

  3. ラウンドトリップの数の最小化: TCP がコネクションのキャパシティを予想するやりかた(スロースタート)のせいで、新しい TCP コネクションはクライアントとサーバーの間の帯域をフルで使うことができない。このせいで、サーバーは新しい接続の最初のラウンドトリップで最大 10 の TCP パケット (~14KB) を送ったあと、輻輳ウィンドウを拡大させ更なるデータを送信するためにクライアントがそれを確認するのを待たなければならない。この挙動を考えれば、ラウンドトリップの数を最小化するために、理想的には、ATF 内のコンテンツは 14KB 以下であるべきだ。そうすれば、たった一度のラウンドトリップでページを描写できることになる。それから、この「10パケット」という数字は最近のアップデート (IW10) で TCP 規格に追加されたものだということも知っておこう。もしこのアップデートにサーバーが対応していなければ、おそらく限界は 3-4 パケットだ。

  4. Above-the-fold 内の JS と CSS をインライン化する: ページをパースしている最中に非同期コードや外部スクリプトに出会ってしまうと、ブラウザは一旦パースを中止してそのリソースをダウンロードしなければならない。そのたびにラウンドトリップが増え、ページのレンダリングを遅くする。
    だから、ATF 内に表示される JS と CSS はインライン化するべきだ。補助的な機能をページに追加する JS や CSS は、ATF コンテンツが表示されてからロードすれば良い。

  5. ブラウザ側でコンテンツをレイアウト&レンダリングする時間を残す (200ms): HTML と CSS をパースして JS を実行するのには時間がかかるし、クライアント側のリソースを使う。デバイスの速度とページの複雑さに応じて、数百 ms かかってしまうことがある。このオーバーヘッドのために 200 ms 残しておこう。

  6. JS の実行 & 表示時間を最小化する: 複雑なスクリプト、非効率なコードのせいで数百 ms かかってしまうことがある。デベロッパーツールをうまく利用して、コードを最適化せよ。 Chrome Developer Tools のインテラクティブコース を受講するのがおすすめ。

注意:もちろん、これはすべての最適化の網羅的なリストではない。パフォーマンスチューニングのためにできることは他にもいろいろある。詳しくは PageSpeed Insights をチェックせよ!特に以下がオススメ。

FAQ

  • 4G だとどうなんよ?

4G マジオススメ。ラウンドトリップのレイテンシが減る。見りゃわかるけど 3G では1秒の半分以上がこのせいで使われてるわけだからな。でも、上で書いたけど、ネットワークとしては今でも 3G が主要だから、かわいそうな 3G 民のことをちゃんと考えてやってくれ。

  • jQuery 使ってるんだが。

うん、そういう JS ライブラリを使ってる奴が多いのはわかる。色々と機能とかアニメーションとか追加できて捗るよな。しかし、こういうことは ATF コンテンツを表示させてからロードすればいいのだ。JS を実行するタイミングを再考せよ。

  • JS フレームワークを使ってるんだが。

コンテンツが JS を利用してクライアントサイドで生成される場合は、まず、JS をインライン化して無駄なラウンドトリップを減らせ。それから、サーバーサイドでレンダリングを行うことで最初のページロードのパフォーマンスは上がる。JS テンプレートはサーバー側でレンダリングし、結果を HTML にインラインで挿入、その後アプリがロードしてからクライアントサイドテンプレートを利用せよ。

  • SPDY とか HTTP 2.0 とかについて詳しく

どちらも TCP 接続をより効率化することでページロードのレイテンシを減らすために努力している。多重化とかヘッダ圧縮とか優先制御とか。SPDY にまず対応し、時が来たら HTTP 2.0 にスイッチするのがオススメだ。

  • どの CSS が一番重要なのかわからん

クロームデベロッパーツールを使え。捗るぞ。

  • めんどくさいから自動化できんのか

おう、商用のものも、オープンソースのものも、ウェブパフォーマンス最適化のための製品はいろいろあるぞ。具体的には このページ を見れ。

  • どういうふうにサーバーをチューンしたらいいんだ?

まずサーバーが最新の OS を走らせていることを確認しよう。TCP の輻輳ウィンドウの拡張 (IW10) に対応するためには、Linux kernel 2.6.39 以上が必要だ。ほかの OS についてはドキュメントを見れ。
サーバーレスポンスタイムの最適化については、何がボトルネックになっているのかを診断するためにアプリケーションモニタリングのためのソリューションを導入すれ。スクリプトの実行なのか、データベースコールなのか、RPC リクエストなのか、それともレレンダリングなのか…。いいか、目標は 200 ms だぞ。

  • Content Security Policy

CSP を使っている場合は、デフォルトのポリシーをアップデートする必要があるかもしれない。

まず、HTML 要素内の CSS 属性を避ける。不必要なコードの重複に繋がるし、CSP を利用しているとデフォルトではブロックされる。JS をインライン化する場合は、ポリシーに “unsafe-inline” を追加して実行を許可する必要がある。デフォルトでは全部ブロックだからな。


以上だ。誤訳があったら教えてくれ。