先日、YSlow が 2.1.0 にバージョンアップされました。リリースノートを見ると、主に次の2つが目に付きます。
img、link、script、iframeタグ、あるいは JavaScript のImage()オブジェクト等において、空のsrcやhref属性をチェックし減点する新たなルール 「画像に対する空のsrcは避けよ」 を追加した。headタグ内に動的にscriptタグを挿入するDeferred Script
は、レンダリングを妨げず、ページ内の他要素と平行にダウンロードされるため、ルール 「JavaScript はページの最後に」 の減点対象としないロジックを追加した。
1. は、空の src があった場合、ブラウザがこれを現在のページと解釈し再度リクエストしてしまう結果、トラフィックが倍になってしまうという問題に対するペナルティーとして追加されました。High Performance JavaScript
の著者 Nicholas C. Zakas は、2009年11月にこの問題を指摘して以来、WHATWG を通して W3C のメンバーに RFC 3986 の不備を指摘し、各ブラウザ・ベンダーにも改善を働きかけてきた問題です。現在はベンダー側もこの問題を認知し、対策がとられるようになったようです。
さて、本エントリーでは 2. をメインに取り上げます。ちょうど前回、Non-Blocking JavaScript
である LABjs というライブラリーを取り上げたばかりなので、私にとってはタイムリーな話題となりました。
1.Deferred Script
って何?
IE は バージョン4 の時代から、script タグに defer 属性を付けると、 (注:DOM 構築 ~ レンダリングのうち、どこまで body 部のレンダリングが終了するまでスクリプトの実行が遅延され遅延されるのか
現在調査中)、その結果、ページ要素の読み込みをブロックすることなく (注:DOM 構築とレンダリングはブロックしないが、読み込みは相変わらずブロックする) 効率良くページを表示することが出来るようになっていました。IE のこの仕様は HTML 4.01 に採用され、XHTML 1.0 DTD、XHTML 1.1 DTD でも定義されています。HTML 4.01 では boolean 属性のため単に <script defer ...> と、XHTML 1.0、1.1 では <script defer="defer" ...> とします。以下は XHTML 1.0 の DTD からの抜粋です。
<!-- script statements, which may include CDATA sections --> <!ELEMENT script (#PCDATA)> <!ATTLIST script id ID #IMPLIED charset %Charset; #IMPLIED type %ContentType; #REQUIRED src %URI; #IMPLIED defer (defer) #IMPLIED xml:space (preserve) #FIXED 'preserve' >
こちらのページで各ブラウザで defer 属性がどう働くかをテストすることが出来ます。このページでは以下の8つのスクリプトが順に埋め込まれ、実行順にメッセージが表示されます。例えば Inline Head
の次に Inline Head Deferred
が表示されれば遅延が効いている事になります。
Inline Head Deferred Inline Head External Head Deferred External Head Inline Body Deferred Inline Body External Body Deferred External Body
IE8、Firefox3.6、Google Chrome1.0 で試した結果を載せておきます。Chrome には 、IE 以外のブラウザもかつては実装されていなかったようです。defer 属性が実装されていませんし
2010年10月25日修正
Chrome 7.0 では外部スクリプトの defer 属性が効きますネ。「Chrome について」 を表示させても 「最新の Chrome です」 となっていたので、7.0 にまで更新されていたのに気付きませんでした
。どのバージョンから実装されたのでしょうか?
この様に Deferred Script
の始まりは結構古いのですが、現在では 「スクリプトの実行」 だけではなく、「スクリプトファイルのダウンロード (Deferred Loading
)」 を、さらには Ajax 技術と組み合わせてスクリプトの実行やダウンロードを非同期的に、並列に行う技術のことも含んでいるようです。事実 JSDeferred とネーミングされた JavaScript ライブラリは、「JavaScript のコールバックによる非同期処理を直列的に書けるようにするために作られたライブラリ」 と説明されています。ただし、この様に書くとまるでスクリプトがマルチスレッドで実行されるような印象を与えてしまいますが、あくまでも JavaScript はシングルスレッドでの実行が基本ですので、ご注意を
。
またスクリプトファイルのダウンロードに限って言えば、本エントリーのタイトルに付けた様に Lazy Loading
とも言われるようです。ページをスクロールして必要になったら画像をダウンロードする jQuery のプラグイン 「LazyLoad」 と同じネーミング・センスですね。
参考情報
- JavaScript: Defer Execution – with the defer attribute of the script element
- Scripts in HTML documents – HTML 4.01
- XHTML Modularization 1.1 – Second Edition – XHTML DTD Module Implementations
- cho45′s jsdeferred at master – GitHub
- High Performance Web Sites :: (down)Loading JavaScript as strings
- On-Demand Javascript – Ajax Patterns
2.JavaScriptの配置とページの読み込み・レンダリング時間のシミュレーション
ここからが本題です。次のそれぞれを組み合わせたパターンに対し、ページの読み込み時間とレンダリング時間がどうなるかを試してみました。
<script>の位置を<head>内に置くパターンと、</body>の直前に置くパターン<script>で普通にダウンロード/実行するパターンと、LABjs を使いダウンロード/実行するパターン
これらのパターンを Cuzillion でシミュレーションしてみた結果が次の図です。<script> タグによるスクリプトのダウンロードを2秒、実行を2秒に設定し、LABjs は 「script DOM element + after onload」 でモデリングしています。

Cuzillionによるシミュレーション結果
この結果から LABjs を使うと 「page load time」 が短くなり、より早く表示されることが分かります。
参考情報
High Performance Web Sites :: Cuzillion
- 「高速サイトを実現する14のルール」の著者 Steve Souders が作ったモデルを使ってブラウザの読み込みとレンダリング速度をシミュレーションするツールです。
3.実際のページによる検証
「iPad風jQueryイメージスライダーをWordPress記事に組み込む」 で使ったサンプルをアレンジして、先の4つのパターンを作成しました。
YSlowスコア
「Put JavaScript at bottom」 は冒頭に挙げた YSlow のバージョンアップが効き、パターン01の head without LABjs
がグレードB、パターン02の head with LABjs
がグレードAとなります。
Firebugウォーターフロー・チャート
LABjs を使った方がブロッキングが少なく、コンテンツである画像の読み込みが終了するまでスクリプトのダウンロードと実行が遅延されています。また DOMContentLoaded イベントが早く発生しており、これは先の Cuzillion によるシミュレーションの結果と良く合います。
レンダリングの開始時間
各パターンが表示される様子を、「ウェッブサイトの表示速度を測定するフリーツール集」 で紹介した 「WebPagetest – Visual Comparison」 のビデオ機能を使い動画にしてみました。
サーバー負荷やトラフィックの状態で多少の誤差はあるとは思いますが、パターン02 ~ 04は2秒弱でレンダリングが開始されるのに対し、パターン01 は、5秒過ぎまでページが白紙のままで、ちょっと我慢ならない状態となりました。
4.まとめ
以上の検証結果から、JavaScript を <head> に置かざるを得ない場合には、LABjs のような Lazy Loading
をするようなライブラリを導入することが、YSlow スコアのアップとページの応答時間の短縮を図る上で非常に効果が高いということが分かりました。
皆さんも導入を検討してみてはいかがでしょうか?
5.その他の参考情報
- 画像に対する空の
src属性に関する Nicholas C. Zakas の情報- 2009年11月22日 Protect IE from empty img src
- 2009年12月30日 Empty image src can destroy your site
- 2010年03月16日 Empty-string URLs in HTML – A followup
- 2010年07月13日 Empty string URLs – browser update








ピンバック: Tweets that mention ゆっくりと… » JavaScriptの”Lazy Loading”とレンダリング時間を検証する -- Topsy.com