動的スクリプト読み込みを使用して、最初のページ読み込みの時間を短縮します。スクリプトで定義された関数とオブジェクトにアクセスできるようにするには、スクリプトが完全に読み込まれていることを確認する必要があります。
私はこの目的のために 私自身のJavascriptライブラリ を開発しました。そのため、さまざまなライブラリでどのように行われるかを研究しながら、このテーマについてかなり多くの調査を行いました。この問題に関連する議論の中で、 LABjs の作者であるKyleSimpsonは次のように述べています。
LABjs(および他の多くのローダー)は、すべてのスクリプト要素に「onload」と「onreadystatechange」の両方を設定します。一部のブラウザーは一方を起動し、一部はもう一方を起動することを認識しています...
この例は この記事の執筆時点でのjQueryの現在のバージョンv1.3.2 :にあります。
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function(){
if ( !done && (!this.readyState ||
this.readyState == "loaded" || this.readyState == "complete") ) {
done = true;
success();
complete();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
head.removeChild( script );
}
};
これは最先端の技術ですが、Opera 9.64での奇妙な動作の分析中に、この手法を使用すると、onloadコールバックの起動が早すぎるという結論に達しました。
私はこの質問に答えるために私自身の発見を投稿し、コミュニティからさらなる証拠とフィードバックを集めたいと思います。
Operaでは、script.readyStateプロパティは信頼できません。たとえば、readyState "loaded"は、スクリプトがOpera 9.64で実行される前に起動される場合があります。
同じテスト in Opera 9.64およびOpera 10で、結果が異なります。
Opera 9.64では、onreadystatechangeハンドラーがスクリプトの実行前と実行後に2回起動されます。どちらの場合も、readyStateプロパティは「ロード」されるため、この値を信頼して検出することはできません。スクリプトの読み込みの終了:
# Fri Dec 18 2009 17:54:43 GMT+0100
# Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1
Test for script.readyState behavior started
Added script with onreadystatechange handler
readystatechange: loaded
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
readystatechange: loaded
Opera 10では、onreadystatechangeハンドラーは値 "loaded"で2回起動されますが、スクリプトの実行後に2回起動されます。
# Fri Dec 18 2009 18:09:58 GMT+0100
# Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10
Test for script.readyState behavior started
Added script with onreadystatechange handler
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
readystatechange: loaded
readystatechange: loaded
これらの異なる動作は、onreadystatechangeがOperaでのスクリプトの読み込みの終了を検出する信頼できる方法ではないことを示しています。 Operaはonloadリスナーもサポートしているため、代わりにこの他のメカニズムを使用する必要があります。
これらのテストの結果に基づいて、onreadystatechangeは、Internet Explorerでのスクリプトの読み込みの終了を検出するためにのみ使用する必要があり、他のブラウザーでは設定しないでください。
Firefox、Safari、およびChromeでは、onreadystatechangeハンドラーが呼び出されることはありません。
短いテストケースを作成し、onreadystatechangeハンドラーセットのみを使用して動的スクリプトを作成しました。
<script type="text/javascript" language="javascript">
bezen.log.info(new Date(),true);
bezen.log.info(navigator.userAgent,true);
// Activate logs
bezen.log.on();
bezen.log.info('Test for script.readyState behavior started');
var script = document.createElement('script');
script.src = 'test1.js';
script.onreadystatechange = function(){
bezen.log.info('readystatechange: '+script.readyState);
};
document.body.appendChild(script);
bezen.log.info('Added script with onreadystatechange handler');
</script>
Firefox 2、Firefox 3、Firefox 3.5、Safari 3、Safari 4、およびChrome 3)のローカルファイルでテストを実行したところ、同様の結果が得られました(ここではログがFF 3.5に記録されています)。
Fri Dec 18 2009 17:53:58 GMT+0100
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6
Test for script.readyState behavior started
Added script with onreadystatechange handler
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
Onreadystatechangeが呼び出されることはありません。これらのブラウザーでは、onloadリスナーのみがスクリプトのロードの終了を検出するのに役立ち、onreadystatechangeは必要ありません。
Internet Explorerでは、スクリプトの終了後、onreadystatechangeハンドラーが期待どおりに起動します。
Internet Explorer 6、Internet Explorer 7、およびInternet Explorer 8で 同じテスト を実行しましたが、これら3つのブラウザー(ここではInternet Explorer 6で記録されたログ)で同様の結果が得られました。
Fri Dec 18 18:14:51 UTC+0100 2009
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Test for script.readyState behavior started
Added script with onreadystatechange handler
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
readystatechange: complete
ここで、ローカルファイルを使用したテストでは、readyStateは常に「完全」であり、数ページの更新後も同じでした。
ただし、 Nicholas C. Zakasによるこの投稿 に記載されているように、さまざまな状況下で「ロード済み」と「完全」、または単に「ロード済み」を観察することもできます。
Internet Explorer(9でテスト)は、readyState === 'loaded'のときに、常にスクリプトの準備ができているとは限らないことがわかりました。私はこのイベントハンドラーを使用して成功しました(もちろん9で)onactivate。以前は髪を抜いていた。
Chromeでも同様の結果が得られます。
準備ができていません...
ただonloadとonerror。