タイトルのとおり
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を無視するならば、その判定方法がスマートですね。