ホーム > XHTML/CSS > ページ読み込み時間を短縮するJavaScriptローダー:LABjs

ページ読み込み時間を短縮するJavaScriptローダー:LABjs

Even Faster Site by Non-Blocking Loading

ブラウザは通常 Web サイトを訪れたとき、CSS や画像などのページ要素を幾つか並列で読み込みますが、JavaScript ファイルを読み込んでいる最中は、(JavaScriptやスタイルシート以外の) 他要素の読み込みをブロックします。それゆえ Yahoo! の 「Best Practices for Speeding Up Your Web Site」 では、それ以上他の要素を読み込む必要のないページ下端に JavaScript を置くことを推奨しているわけです。

これに対し 「ハイパフォーマンスWebサイト―高速サイトを実現する14のルール」 (今は35のルールですが) の著者 Steve SoudersNon-blocking JavaScript、つまり他のページ要素をブロックしないファイルの読み方を提唱しています。LABjs は氏の監修の下で作成されたオープンソースの JavaScript ライブラリ (MIT ライセンス) です。本エントリーではその使い方と効果を検証してみたいと思います。

動作原理

Steve Souders 氏によれば、Non-blocking Loading の方法は次の6つがあるそうです。

  • XHR Eval
  • XHR Injection
  • Script in iframe
  • Script DOM Element
  • Script Defer
  • document.write Script Tag

LABjs はこのうち XHR (Ajax) と Script DOM Element とを組み合わせた、非同期 JavaScript ローダーです。またブラウザに他のリソースをロックさせないよう、読み込んだ JavaScript ファイルの MIME タイプを text/html とし、実行前に text/javascript に戻すというトリックを使っているようです。このトリックを念頭においておくことが使いこなしのポイントと思います。

使い方

次の様な幾つかの JavaScript ファイルの読み込みと実行を指示する HTML があったとします。

<html>
<head>
	<link href="style.css" type="text/css" media="screen" />
	<script src="jquery.js" type="text/javascript"></script>
	<script src="jquery.ui.js" type="text/javascript"></script>
	<script src="jquery.lightbox.js" type="text/javascript"></script>
</head>
<body>
...
<div id="gallary">
	<!-- ギャラリーアイテム -->
</div>
<script type="text/javascript">
	$(document).ready(function() {
		$('#gallary').lightbox();
	});
</script>
...
</body>
</html>

これに LABjs を適用するには .script() に必要な JavaScript ファイルを指定して連結します。

<html>
<head>
	<link href="style.css" type="text/css" media="screen" />
	<script src="LAB.js" type="text/javascript"></script>
	<script type="text/javascript">
		$LAB
		.script("jquery.js").wait()
		.script("jquery.ui.js")
		.script("jquery.lightbox.js")
		.wait(function() {
			$(document).ready(function() {
				$('#gallary').lightbox();
			});
		});
	</script>
</head>
<body>
...
<div id="gallary">
	<!-- ギャラリーアイテム -->
</div>
...
</body>
</html>

LABjs では .script() で連結されたファイルは非同期に並列で読み込まれることに注意してください。ゆえに JavaScript 相互に依存関係がある場合には .wait() によって同期を取らなければなりません。上の例では、jquery.ui.jsjquery.lightbox.jsjquery.js の読み込みが終了していない場合はエラーを起こすので、.wait() を指定して同期の保証をします。LABjs 適用前でも Firefox などのモダンブラウザでは JavaScript ファイルを並列に読み込みますが、ブラウザは読み込むべき順番を知っているので、同期的に依存関係を解決してくれていたわけです。

またスクリプトの実行は、一連の連結の後にやはり wait() の引数内を通して指定されなければなりません。「動作原理」に書いたトリックを思い出してください。通常のインライン・スクリプト

<script type="text/javascript">
	$(document).ready(function() {
		$('#gallary').lightbox();
	});
</script>

では、前述の非同期ローディングのトリックを解決できないため、実行が出来ないのです。

使用上の注意

LABjs にはこれ以外にも幾つかの注意事項があります。

LABjs 自体のローディング

Snippet to load LABjs itself dynamically にあるコード・スニペットをインラインのスクリプトとして記述すれば OK です。お勧めの構成は、導入ページにインライン・スクリプトを配置し、次ページ以降は通常の <script> タグで読み込むことです。こうすればキャッシュから読み込むことになるからです。

ユーザーのエクスペリエンス

従来ページに LABjs を適用すると、コンテンツが表示される前にスクリプトが読み込まれ実行される可能性があります。これにより、JavaScript でコンテンツのスタイルを変えているようなページの場合、スタイル適用前の生のコンテンツが見えてしまったりします。つまり LABjs 適用後は各ブラウザでどう見えるかを考える必要があるのです。この考え方は 「プログレッシブ・エンハンスメント」 (古いタイプのブラウザにも必要機能を提供し、より革新的なブラウザにはリッチなコンテンツを提供すること) によくマッチします。つまり、より 「プログレッシブ」 の部分が際立つのです。しかしながら、多くのスタイルをスクリプトで変えているようなサイトの場合、その修正は大変です。こんなときは、CSS で display: none あるいは visibility: hidden 等によりスクリプトによって再レンダリングされる全てのコンテンツを隠すと良いでしょう。もちろん、スクリプトを有効にしていないユーザーのために <noscript> で画されたコンテンツを表示するように CSS を指定することを忘れてはいけません。ただし Valid な HTML にはなりませんが…。

document.write()と一緒には使えない

LABjs は非同期ローダーですが、document.write() は本来同期的であるため、LABjs の非同期技術を壊してしまいます。appendChild() 等を使って DOM 要素を追加するスクリプトに変えなければなりません。

安全でないDOM-ready状態を検知する特定のJavaScriptフレームワーク

jQuery 1.4 未満は DOM-ready の発生以降にスクリプトが読み込まれた場合、2度と DOM-ready が発生しないため、スクリプトが実行されないという不具合があります。これは Jquery のバグとして報告されていて、バージョン 1.4 で修正されるはずだと書いてあります。 $(document).ready(function(){…}); を使うスクリプトは注意しましょう。

ローカル環境でのテスト

LABjs は XHR を使うため、ローカルではテストが出来ません。そこで LABjs をダウンロード/解凍して出来る fLAB.js を使います。fLAB.jsLAB.js のラッパーとして機能します。

<script src="LAB.js" type="text/javascript"></script>
<script src="fLAB.js" type="text/javascript"></script> <!-- 開発環境のみ -->

効果検証

jQuery 1.4.3 と Nivo Sliderlightbox を使ったサンプルを用意しました。サンプル3 はオマケです。サーバーやネットワークの状況にもよりますが、「使用上の注意」 で述べたように DOM-ready が検知でずにスライドショーが始まらない事象が頻発すると思います。

それぞれのYSlow のウォータフォール図を並べてみると、ページ全体の読み込み時間に差はありませんが、メインコンテンツである画像を読み込む時間 (DOMContentLoaded) は LAB 適用前が 820msec であるのに対し、LAB 適用後が 260msec となり、体感できるほどに短縮できていることが分かります。

LABjs適用前

LABjs適用前

LABjs適用後

LABjs適用後

また LABjs 導入前後におけるレンダリングの様子を、「WebPagetest – Visual Comparison」 でビデオにしてみました。LABjs 導入後の方が、描画が早く開始している事がよくわかります (2011年5月31日追記)。

Loading the player …

スクリプトのローディングとレンダリングのブロックについては、以下の記事にも詳しく書きましたので、参照して下さい。

2010年10月18日追記

余談ですが、サンプル1、2 はIE6でエラーが出ることが分かりました。画像自体は切り替わるのですが、切り替わり時のエフェクトが動作しません。そこでサンプル4、5 として jQuery 1.4.2 版もアップすることにしました。Nivo Slider を使うときは 1.4.3 は使わない方がよいかも知れません。

参考情報

JavaScriptローダー関連

Steve Souders

Stoyan Stefanov

カテゴリー: XHTML/CSS タグ: ,