タイトルのとおり
Google Chromeは大変速いブラウザですが、その速さ故か、たまにDOMContentLoadedが発生しないケースがあります。以下のようなコードで再現確認できます。
HTML
<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <title>domcontentloaded test</title> </head> <script type="text/javascript"> (function(d){ d.addEventListener('DOMContentLoaded', function(){ alert('nya-'); }, false ); var s = d.createElement('script'); s.src = 'hoge.js'; s.charset="UTF-8"; var h = d.getElementsByTagName('head')[0]; h.insertBefore( s, h.firstChild ); })(document); </script> <body> <h1>debug</h1> </body> </html>
JavaScript(hoge.js)
document.addEventListener('DOMContentLoaded', function(){ alert('nya-2'); }, false );
解決策
window.onloadにイベントを割り当てましょう。具体的には以下のコード
var isLoad = false; document.addEventListener('DOMContentLoaded', function(){ isLoad = true; alert('nya-2'); }, false ); window.addEventListener('load', function(){ if( !isLoad ){ alert('nya-2'); } }, false );
最後に
この現象は、たまたま今日見つけたものです。もしかしたら、僕の環境だけで発生するレア現象なのかもしれませんが、同様のケースで困った方がいらっしゃいましたら、何かの参考にして頂けたら幸いです。
DOMContentLoadedが発生しないのではなく、後から追加したscript要素内でDOMContentLoadedに登録してもDOMContentLoadedの発生に間に合わないことがあるってことですよね。
返信削除createElementして追加したscript要素の実行タイミングは保証されていないので、Chromeに限らず、DOMContentLoadedに間に合わない可能性はあります。(といいつつ、FirefoxとOperaの実装では実行タイミングを保証しています)。
>os0xさん
返信削除コメントありがとうございます。
>DOMContentLoadedが発生しないのではなく、後から追加したscript要素内でDOMContentLoadedに登録してもDOMContentLoadedの発生に間に合わないことがあるってことですよね。
って事です。
難しいですね、日本語。
とりあえず、hoge.js を以下のようにすると動作するようです。
返信削除---
(function (loadedListener) {
var doc, readyState;
doc = document;
readyState = doc.readyState;
if (readyState === 'complete' || readyState === 'interactive') {
loadedListener();
} else {
doc.addEventListener("DOMContentLoaded", loadedListener, false);
}
})(function () {
alert('nya-2');
});
---
document.readyState === 'interactive' 以上が保証されれば、DOMContentLoaded 以降のタイミングのはずなので問題ないと思います。
このままでは第一引数で event を受け取れないのがネックですが。
>think49さん
返信削除コメントありがとうございます。
documentのreadyStateを使う方法は試したのですが、IE(憎き奴です)で上手く行かなかったので、諦めました。
ただ、IEを無視するならば、その判定方法がスマートですね。