Nicholas C. Zakas「Loading JavaScript without blocking」
NCZOnline、2009.6.23のエントリ
Loading JavaScript without blocking
Steve Soudersの同名エントリLoading Scripts Without Blockingへのリプライ記事。
Soudersのエントリでは、他のコンポーネントのロードをブロックしないjsロードのためのテクニックが、XHR使用2つ、iframe使用2つ、DOM使用1つ、script[defer]使用1の5つ紹介されてるが、各テクニックの実装サンプルは割愛されてる(書籍では、サンプルコード載ってる)。
Zakasは「DOM使用」タイプ(オンザフライでscript要素生成しjsロードするテクニック)について、3本立ての補足
- サンプルコード
- プラスアルファでコールバック指定したい場合のサンプルコード
- その際のクロスブラウザ化のポイント(IE対策)
- YUI3も実装済なことを例に即して
以下斜め読んだ内容
- Soudersのエントリで紹介されてたオンザフライでscript要素生成しjsロードするテクニック
- サンプルコード内から書いた
var script = document.createElement("script"); script.type = "text/javascript"; script.src = "file.js"; document.body.appendChild(script);
- 機能追加:jsロード終わったらコールバック指定できるようにしたい
- IE以外はscript要素にloadイベントにセットすればいい、カンタン
- IE対策
- (script要素では)loadイベントない
- 代わりにreadyStateプロパティとreadystatechangeイベント(readyStateの値の変化をキャッチする)で実装
- readyStateプロパティはMSDNに書かれてることと実情が違うから注意
- 「仕様では」readyStateプロパティが取りうる値は5つ
- uninitialized
- デフォルト
- loading
- DL開始
- loaded
- DL完了
- interactive
- データはアクセスできるが十分にアクセスできない
- complete
- データにアクセスできる状態になってる
- uninitialized
- readyStateプロパティの実際の動きで問題になる点
- どんどん状態変化していってcompleteになるはずなのに、ならない場合あり
- loadedでストップする場合がある。
- なので、loadedかcompleteになったらコールバック実行という風に実装すればよい
//Internet Explorer only var script = document.createElement("script"); script.type = "text/javascript"; script.src = "file.js"; script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; alert("Script is ready!"); } }; document.body.appendChild(script);
- あとはクロスブラウザ対応用にIE以外とIE用をラップする関数にするだけ
- 話は戻って、オンザフライでscript要素生成しjsロードするテクニックはYUI3でも使ってるテクニック
- 他のコンポーネントをブロックしないでjsロードしたいとき、YUI使ってるひとはすぐできるよ
YUI().use("dom", function(Y){ Y.DOM.addClass(document.body, "active"); });
- 上のYUI依存のコードがやってること
感想
loadedでストップしたりcompleteでストップしたりする理由が分からなかったけど、「外部JavaScriptの動的ロード - 0xFF」読んだ。
- キャッシュされてないjsは、loaded
- キャッシュされてるjsは、complete
と理解した。