jump to navigation

javascriptでのパフォーマンスチューニングについて 6月 5, 2009

Posted by hyhy in 技術情報.
Tags: ,
trackback

JavaScriptとWebページの表示・操作の体感速度について改善する方法についてまとめました。

■JavaScriptファイルの読み込み時間を短縮する
1)JavaScriptはHTMLに含めず,別ファイルとして用意すること
JavaScriptのファイルがHTMLとは別にキャッシュされ,キャッシュの効率が上がることが期待できます。
しかしながら、キャッシュが空の状態でアクセスした場合、効果はありません。

2)ファイルのサイズを小さくすること
・JavaScriptのファイルから,コメントや空白を取り除いたりする「圧縮」加工をして,ファイルサイズを小さくします。
自動ツール YUI Compressor
※一度圧縮処理をしてしまったJavaScriptファイルは,メンテナンスをするのが困難になってしまいます。

・HTTPには転送時にgzip圧縮を行って転送量を減らす「HTTP 圧縮(HTTP compression)」という仕組みがあり、JavaScriptはテキストファイルなので,これを行うと効果があります。

・複数のjavascriptファイルをひとつにまとめることで、HTTPリクエストの頻度を減らし、オーバーヘッドを削減します。

■実行のタイミングなどを工夫して体感速度を上げる
実際に個々の処理にかかっている時間は変わらないものの,そのタイミングをずらすことで,待ち時間を減らします。

ページ内のJavaScriptを実行する際のタイミングとして良くあるのは,
・ページ内でそのJavaScriptが読み込まれた時
・ページの構築がすべて終了した時
(ページ内のHTMLが解析し終わって,画像も読み終わり,ページのレンダリングがすべて終了したタイミング)
JavaScriptではload(onload)イベントを利用することで,そのタイミングを知ることができ,そこで指定した処理を実行することができます。

【loadイベントの問題点】
ページのロードが終了した段階で,たくさんの処理を行ってしまうと,「ページの読み込みが終わってからJavaScriptの処理のためにページが一瞬固まる」という現象が発生してしまいます。
また,loadイベントが発生するのは,画像も含めてすべてのデータがダウンロードされたあとになります。そのため,読み込みの遅い画像(アクセスに時間がかかる,もしくはファイルサイズが大きいなど)があると,その画像の読み込みが終わらないことには,処理が実行されないことになってしまいます。
————————————————————

本題に入りまして、
通常のブラウザでは,画像の読み込みが完了していなくても,ユーザーはページの内容を読んだり,リンクをクリックしたりすることができます。そのため,例えばある場所をクリックしたときに,アニメーションを行う,といった処理をloadイベントでセットしようとしていた場合には,画像の読み込みが完了する前にクリックされても,正しく動作しなくなってしまいます。この点を考慮する必要があります。

そこで登場する、
 「DOMContentLoaded」イベントは、ページを構成するHTMLの解析が終わった段階で発生します。もし,まだ読み込みが終わっていない画像が存在していても,それとは無関係です。したがって,どんなに読み込みに時間がかかる画像があったとしても(それはそれで問題ですが),ページのHTMLが構築された段階で,JavaScriptの処理を実行することが可能です。

【結論】
 JavaScriptの実行と画像の読み込みが平行して行われるようになり,その結果,すべての処理が完了してページが動作できるようになるまでの時間が短縮され,ユーザーの体感速度を上げられるわけです
1)HTMLの読み込み
2)HTML解析 DOM構築→終了時:DOMContentLoadedイベント発生
2.1)画像の読み込み→終了時:loadイベント発生

※ただし,「DOMContentLoaded」イベントはFirefoxとOperaでは用意されていますが,Internet ExplorerやSafariでは使うことができません。しかし,それぞれのブラウザで,それに近いことを行うテクニックが考え出されています。PrototypeやjQueryなどを使うことで対応可能です。
jQueryサンプル

 また,「タイミングをずらす」ための別の方法として,初期化の処理を,初めてそれが必要になったときまで行わない,という方法も考えられます。ページがロードされたときに行う処理の中には,何かがクリックされたときなどのための「初期設定処理」が多く含まれがちです。しかし,それらの数が多くなってくればくるほど,ページロード時に行うべき作業は多くなってしまい,その分時間がかかってしまいます。そこで,そうした初期化の処理をページ読み込み時には行わず,実際に初めてクリックされた(もしくは初めてその処理が実行されるトリガが引かれた)際に行うようにするわけです。

 例えばあるボタンをクリックすると,小さなサブウィンドウ(実際のウィンドウではなく,ページ内に埋め込まれた要素として表現されているもの)を開き,そこで何らかの操作をするものがあったとします。そのウィンドウの構築をページのロード時ではなく,例えば初めてボタンがクリックされたときに行うなどすれば,処理を分散できるでしょう。

 この場合,初期化作業が発生する最初の1回は,2回目以降よりも時間がかかってしまいます。しかし,まとめると大きな時間になる初期化の処理も,一つ一つにばらせばそれぞれは短い時間になりますし,まとめてやるよりは速度の低下を防げるはずです。こちらの場合は,処理のタイミングを「分散させる」ことで,体感速度の低下を防ぐというわけです。

■JavaScript自体の処理速度を上げる工夫をする
ページが読み込まれた際に実行されるJavaScriptの実行タイミングを後ろにずらします。
ページの表示中にJavaScriptが実行されると,その実行が終わるまで,ページの続きが表示されなくなります。したがって,時間がかかる処理は,ページのロードが終わったときなどに実行するように,その場では処理の呼び出しをセットするだけにとどめるようにするわけです。

もう一つ,読み込みを遅延させる対象として効果的なのが,画像です。
画像の遅延ロードを実現している例として,jQueryというJavaScriptライブラリのプラグインに「Lazy Load Plugin for jQuery」というものがあり,これがまさに画像の遅延ロード(英語ではlazy loadと呼びます)を実現しています。

■その他
* DOMContentLoaded ですら遅いので、HTML 生成時に script 要素を各所に埋めこんで処理を先走りさせる
o DCL 前に通信を開始できるなら意味があるかもしれない
o document.write する script (広告とか) があると DCL が遅延するので価値があがる
* 初期表示に必ず XHR による通信が必要なコンテンツを localStorage にキャッシュして次回はとりあえずそれを表示させてから通信を走らせる
o ユーザを一瞬騙すけど気持ちはよくなる
* JSONP を Cross Origin XHR に置きかえる
o ステータスバーに余計な表示がでない分気持ちよくなる
o URL が長くなりすぎる場合、POST でリクエスト数を減らせることがある
* エフェクトの実行時間自体を半分にする、あるいはなくす
o というかエフェクトは基本的に通信が同時に走るとき以外はしない、というルールにしたほうがよい
+ 通信が入る場合はエフェクトが入ったほうが待っている時間が短かく感じる
* とりあえずでもいいのでユーザのアクジョンの結果は先にだす
o アクション → 未確定 → 確定とちゃんと見た目が遷移するように

参考サイト
JavaScriptを高速化する6つのテクニック

広告
%d人のブロガーが「いいね」をつけました。