JavaScript
Node.js
AngularJS
Synth
AngularJSDay 16

初回レンダリング完了までの時間を短縮するためのpreloadについて

More than 3 years have passed since last update.

これは AngularJS Advent Calendar 2014 の12/16の投稿です。

この記事はAngularJSってより、フロントエンドフレームワークの新しい手法について書いてあります。
枯れた技術しか好まない方、日本語の記事が揃うまでは何が何でも手を付けたくない方は来年のアドベントカレンダーにご期待ください。

概要

AngularJS等のフロントエンドフレームワークにはレンダリング完了までの時間が、通常のページに比べて、DOMの構築する手順が増えた分、とてもコストの多い作業となっています。
それらに関して、Twitter Mobileで採用された1つのアプローチを紹介したいと思います。

歴史

昔(と言ってもまだ10年経ってない)からJavaアプレットやフラッシュ、Flex、ASP.NETなど、沢山のブラウザ上で動くリッチなアプリケーションが生まれては大きな堅い企業の一部を除いて消え、を繰り返していた、世界をW3Cはまだ見放しては居ませんでした。彼らはHTML5とCSS3を与え、サイトのデザイナーは覚えることが増えたが、実現可能なデザインの幅が広がり、ブラウザの開発者は他者の実装に遅れまいと必死に実装するのでした。

話が進みすぎてしまったため、時を一旦戻します。
みんな大好きAjax、みんなjQueryを使いたがりますが、私はprototype.jsの方が好きです。
まぁAngularJS登場以降はそれも使うことは無くなってしまいましたが。

Ajaxというワードは遡ること2005年に誕生しました。
Googleを筆頭に、ブラウザのページ偏移無しでアプリケーションがブラウザ上で動く様を魅せつけられました。
しかし、当時の実装はとても面倒くさく、まともなUI/UXを誰でも実現できるというものではなかったです。

時は2009年!!あのAjaxをいち早く導入したGoogleがまたまた爆弾を投下しました。それがAngularJSです。
フロントエンドでもフレームワークを用いることによって、より自由度の高いブラウザアプリケーションを楽に構築できるようになりました。

そして、今現在はSinglePageApplicationと呼ばれる、ベースのHTMLの中で全てのアプリケーションを完結させてしまう手法が主流になっています。

仕組みとしては、ベースのHTMLとJSONなりXMLを返すAPIサーバーとページごとのパーツとして分割されたHTMLに分けられます。

これらは初回レンダリングの際、以下の手法で読み込まれています。
Untitled Diagram.png

現状の問題点

このような手法での問題点は、ページのベースとなるHTMLのレンダリングが完了してからコントローラーが呼ばれるだけでも重いのに、そこから更にAPIを叩いてから、それをレンダリングするまで多大なコストが掛かることです。
また、第一段階として、ベースのHTMLの読み込みが完了してから、大量のテンプレート用のHTMLを読み込んで、複数個のコントローラーをDLしていると、それも多大な時間がかかります。
快適な光回線ならまだしも、低速な回線や低スペックな端末ですと、いつまでも目的のページが表示されないことがあります。

以下の点についての打開策としては

  • そもそもシングルページでやらない
  • キャッシュを最大限に活用したり、必要なライブラリ群はminifyしてconcatする
  • preloadの利用

まず、一つ目は却下で。

2つ目なのですが、必ずしても良いと思います。某、SF漫画の主人公のようにminifyしてconcatは実行しておくべきだと思います。手動でやっても良いのですが、面倒なのでGruntやGulp等の自動的にファイルの変更を検知してビルドしてくれるツール等を用いると開発が楽になるかと思います。

次に、3つ目なのですが、これが一番効き目があります。
ベースとテンプレートのHTMLがレンダリング完了して初めてAPIを叩きだすのは、初回のレンダリングにはとても重いものとなります。そこで以下のような手法があります。

Untitled Diagram-1.png

この図ではページHTMLの中に埋め込まれていようように見えますが、実際にはベースとなるHTMLの中に埋め込まれています。
これはHtml5Modeを利用する際に最大限の効果を発揮します。
Html5Modeを使うときにベースのHTMLはどうやって取得していますか?
普段はroutingしてAPI以外はベースのHTMLを返しているかもしれません。
つまり、そのHTMLの中に初回叩かれるであろうAPIを埋め込んでおくことで、ユーザーになるべくはやくレンダリング済みのページを提供することが出来ます。
一度レンダリングが終了してしまえば、後はバッググラウンドでAPIを叩けば良いため、非常に初回レンダリングがスムーズになります。

この手法は今現在、モバイル版のTwitterで導入されています。
昔のTwitterのページは、一度ベースとなるパーツが全て読み込み終わってから初めてAPIを取得していたため、TLの表示がとても遅いものでした。
しかし、今現在のTwitterはpreloadを最大限利用することによってページの表示速度が格段に改善されました。

preloadを気軽に利用する

一番簡単なのは、node.jsのフレームワークであるSynthを利用することです。
もうここまで書いて面倒になったので、数カ月前に書いた私の記事を参照して下さい。
AngularJS - Synthってなんじゃらほい? - Qiita

このフレームワークはExpressをベースにしており、また、静的なコンテンツの配信にStを採用していたりと、色々とモダンな実装が多々あり、Expressで開発をする際にの参考にも鳴るかと思います。

また、フロントエンドとバックエンドのライブラリをsynthコマンドで一元管理できるのも利点の一つで、本当はこのアドベントカレンダーに合わせてSails版のSynthを公開したかったのですが、間に合わなかったので、そのうち別途公開します。

まとめ

  • AngularJSではテンプレートやJS部分を極限まで圧縮して一つにまとめる!
  • 便利なツールは積極的に使っていこう
  • APIに関しては積極的にpreloadを用いることによって初回の表示時間を大きく短縮できる

本日は最後までご覧頂きありがとうございました。