
ちょっと前に 「scriptのdefer/asyncを理解し、ページの高速化方法を探る」 というエントリーを書きましたが、はてなのブックマーカー edvakf さんから 「Opera は defer も async も対応してないはず」 というご指摘を頂きました (edvakf さん、ありがとうございます)。
こちら と こちら (2012年11月16日:Google のドキュメントが削除されました) の表を 「対応状況」 としてそのまま流用してしまったのが失敗でした。英語をよく読めば、You can use the defer/async attribute on the following elements
と書いてあります。つまり 属性は使えるけど、動作は別
とも読めるわけで…。
ということで、「defer/async チェッカー (仮)」 を作ってリベンジすることにしました。
1.defer/asyncチェッカー(仮)
一応 Cuzillion をヒントに作っていますが、「チェッカー」 といっても自動チェック機能はなく、目視でチェックするヘボなツールです。その特徴は次の通りです。
- ドキュメントタイプの切り替えと
defer、async属性の On / Off - スクリプト実行 (DOM への文字挿入) 状況を確認する機能
- JavaScript ファイルの読み込みに時間差を付ける機能
- イベントの発生順序、およびオブジェクト状態の変化順序を確認する機能
document.write()利用時の影響を確認する機能
1.1動作原理
以下の様に、メインコンテンツ部分 「Hello」 と 「World!」 のパラグラフ間に3つのスクリプトを挟み、各スクリプトはそれぞれ 「A」、「B」、「C」 というパラグラフを生成します。それぞれは2秒、1秒、0秒の待ち時間の後にスクリプトを送出しますので、DOM の構築がブロックされる様子を確認することが出来ます。即ち defer、async が有効であれば、いち早く 「Hello Wold!」 のコンテンツが完成するわけです
。
HTMLの主要部分
<div id="main"> <p>Hello</p> <script type="text/javascript" id="A" src="script.php?id=A&wait=2000" defer></script> <script type="text/javascript" id="B" src="script.php?id=B&wait=1000" defer></script> <script type="text/javascript" id="C" src="script.php?id=C&wait=0" defer></script> <p>World!</p> </div> <!-- main -->
属性の指定方法は、HTML 4.01 と HTML5 では単に defer、XHTML1.0/1.1 では defer="defer" となります。ドキュメントタイプと属性の指定方法については 「scriptのdefer/asyncを理解し、ページの高速化方法を探る」 にまとめてありますので、そちらを参照ください。
JavaScript (A、B、C の3種類)
var e = document.createElement('p');
e.innerHTML = 'A'; // 'B', 'C'
document.getElementById('main').appendChild(e);
JavaScript を生成する script.php
上記3つのスクリプトファイル生成時に、引数として wait=2000 (2秒スリープ後にスクリプトを送信) に様に、時間差を付ける機能を実装しました。
1.2確認方法
属性無し あるいは 非対応

右図の様に、スクリプトのローディングにより 「Hello」 以降の DOM 構築がブロックされます。「A」、「B」、「C」は同時にローディングされていますが、その評価・実行順序は保持されるので、2秒後、ほぼ同時かつ A → B → C の順に DOM が挿入され、「World!」 でページの表示が完成します。
deferが有効

「Hello World!」 までの DOM 構築が先に行われます。一方、スクリプトはローディングはされていますが、その評価・実行は DOM 構築完了まで遅延されます。かつその順序は同期的に保存されます。
asyncが有効

「Hello」 の DOM 構築後、各スクリプトのローディングが非同期に開始されます。またローディングが終了した順に非同期に評価・実行が行われるため、C → B → A の順に表示されることになります。仮に 「World!」 が画像で、そのローディングにも時間がかかる様な場合には、「C」 の方が先に表示されることもあり得ます (事実、キャッシュからのローディングの場合には、そうなる可能性が高い)。
1.3イベント or 状態のログについて
オマケで、オブジェクトからのイベント (DOMContentLoaded と onload) や状態 (readyState) の変化をキャプチャしてログする機能を付けてみました。Firebug のを開いていれば、コンソールにリアルタイムにログを出力しています。
readyState Property – MSDN Library に readyState の定義がありますので、掲載しておきます。
| 名称 | 状態 |
|---|---|
uninitialized |
オブジェクトはまだ初期化されていない |
loading |
オブジェクトはデータをローディング中である |
loaded |
オブジェクトはデータのローディングを完了した |
interactive |
完全にロードされたわけではないが、ユーザはオブジェクト関わることができる |
complete |
オブジェクトは完全に初期化された |
interactive の意味は、「プログラムは実行可能だよ」 とか 「DOM の一部はアクセス可能だよ」 とかだと思います。
また、例として Firefox と IE8 のログを載せておきます。特に IE は、script 要素にも readyState があるのが分かります。ブラウザの中身がちょっと覗けたような感じがして、ちょっぴりウレシイです。
参考情報
2.主要ブラウザの対応状況
さて、ヘボなチェッカーで手持ちのブラウザを確かめてみました。
| ブラウザ | HTML 4.01 | XHTML 1.0/1.1 | HTML5 | |
|---|---|---|---|---|
defer |
defer |
defer |
async |
|
| IE6 | Y | Y | Y | N |
| IE7 | Y | Y | Y | N |
| IE8 | Y | Y | Y | N |
| Safari4 | N | N | N | N |
| Safari5 | N | N | N | N |
| Opera10 | N | N | N | N |
| Chrome7 | Y | Y | Y | N |
| Chrome8 | Y | Y | Y | Y |
| Firefox3.6 | Y | Y | Y | Y |
IE は HTML5 に対応しているというより、属性の指定方法が HTML 4.01 と同じため、機能しているということだと思います。またいつの間にか Chrome が 7 から 8 にアップしていて、async に対応していました。Safari などは、defer 属性値を持っており、true をセットすれば、それが保持されるようです。だからといって非同期読み込み・実行がされるわけではないのですネ。



ピンバック: Tweets that mention ゆっくりと… » defer/asyncチェックツールを作りブラウザ対応状況を確認してみた -- Topsy.com