JavaScript > 動的なscriptタグの読み込みを同期的に行う

2008年08月31日

タイトルからして何を言っているか分からないと思いますが、 JavaScriptから動的にscriptタグを追加した場合に、非同期に読み込まれるという 特徴があるのですが、これを同期的に読み込もうというお話です。

動的なscriptタグの追加

JavaScriptからscript要素を作り、追加する事で外部JSのロードを行うという処理です。 外部JSファイルの読み込みや、いわゆるJSONPとかです。

動的に追加した場合の特性として、読み込みが非同期になるというものがあります(operaは9.5からのようです)。

これは使いようによっては便利でもあり不便でもあって、 非同期読み込みの特性を利用すれば、ページ読み込みの高速化にも利用出来る(JavaScript読み込みブロック回避でページ表示を高速化する方法 | エンタープライズ | マイコミジャーナル)のですが、 ライブラリの依存関係を考慮して、順番に読み込む場合等には非同期で読み込まれると困ります。

ブックマークレットから外部ライブラリをいくつか読み込む時に困ったので、 scriptタグの読み込みを同期的に行えるようにしようという事で、少し前にライブラリを書きました。

JSLoader - labs.37to.net

ライブラリの紹介は後半にするとして、同期的に読み込む為のアプローチを書いていきます。

問題点

scriptタグの読み込みの完了が捕捉出来れば、コールバック関数を使って、順番にscriptタグを追加するという事が出来るのですが、例のごとくIEでつまずきます。

IEでscriptタグの読み込み完了が捕捉出来ない
残念ながらIEはscriptタグのonloadが使えないのです

setIntervalやsetTimeoutを使う

同期的に読み込む試みは以前から行われていて、定期的に話題に上がっているのですが、 そこで行われているのが、setIntervalやsetTimeoutを使うという試みです。

簡単に説明すると、

  1. scriptタグの追加
  2. タイマーを使って、追加した外部JSの変数が定義されるかどうかを監視
  3. 変数が定義された事を確認した時に、次のscriptタグを追加する
  4. 上記を繰り返して、順番にscriptタグを追加していく

という処理を行い、scriptタグを順番に読み込む方法があります。

この方法には欠点があって

  • 外部JSで定義される変数を知っておかないといけない
  • そもそも変数を定義せず、処理だけを走らせる外部JSでは読み込みが完了したかどうか分からない

という問題があります。

そこで色々調べた結果、実装したのが次の方法です。

IEはonloadの代わりにonreadystatechangeを使う

タイマーを使う以外に方法はないかとMSDNを漁っていると、IEはonloadが使えない代わりにonreadystatechange が使える事が分かりました(ちなみにMSDN上ではonloadが使えるらしいのですが動作せず・・・)。

これを使えば、readyStateプロパティに読み込み状況が保存され、このプロパティが変わる度にonreadystatechangeのイベントが呼ばれます。 そしてこのイベント内で、readyStateが読み込み完了の時に任意の関数を呼び出すようにすると、コールバック関数が使えるようになります。

onloadと同等の事が出来るようになるので、後はコールバック関数を使って順番に外部JSを読み込む処理を書くだけです。

クロスブラウザな外部JSのロード関数はos0xさんの所で書いてくれています。
外部JavaScriptの動的ロード - 0x集積蔵
その他のアプローチも書いてあって参考になるので、ぜひ一読を。 蛇足ですが、読み込み完了時のreadyStateの値はキャッシュあり=comlete, キャッシュなし=loadedとなるようです。

外部スクリプトを読み込むJSLoder

onreadystatechangeを使って、scriptタグを同期(又は非同期)に読み込みつつ、間に処理を挟めるように作ったのが、JSLoderです。

サンプル


new JSLoder({
    finish : function(){
        console.log('全ての読み込み完了');
    }
})
.next('first.js')
.next(function(){
    console.log('firstの読み込み完了')
})
.next('second.js','third.js')
.next(function(){
    console.log('secondとthirdの読み込み完了')
})
.start()

という感じでJSDeferdっぽく処理が出来るようになります。

これを使えば、ブログパーツ等も多少すっきりと書けます。(内部でdocument.write()等を使っていると、恐らく動きませんが)

詳細は以下から

JSLoader - labs.37to.net

おまけ

動的ローディングについてのリソース

まとめると、IE--。

posted by 37to at : 20:01 | コメント (0) | トラックバック (0)

コメント

この記事に対するコメントはまだありません。


投稿する

投稿者情報を保存しますか?


トラックバック

トラックバックURI


一覧

この記事に対するトラックバックはまだありません。