以前に、window.onloadの代替スクリプトGの記事を書いていたんですが、今はちょっと違ったスクリプトになっているので、この辺で、まとめもかねてメモを。
今ではどのJavaScrptライブラリーも、画像も含めたページ読み込み完了まで待って、つまりwindow.onloadのタイミングで初期化関数を走らせるなんてことはせずに、もっと早い段階、つまりブラウザがDOMの構造を把握してパースしたタイミングを見計らって、初期化関数を実行するようにしています。Firefox、Operaでは、ブラウザ側がDOMContentLoadedというイベントハンドラを用意してくれているので、これを使います。Safariがこれを採用するのも時間の問題だろな、と前々から思っていたんですが、昨日、Safari最新版(3.1.1)も対応しているっぽいことに気が付きました。こういうスクリプト を書いて、イベントの発火順序を調べていたんですが、何気にSafariで動いているんでちょっとビックリしました。
イベントの発火順序を調べる→http://p2b.jp/demo/events-order.php
IEに関しては、DOMContentLoadedというイベントハンドラはないので、以前から色々なアプローチが取られてましたが、今ではbase2 のDean Edwardsも、jquery のJohn ResigもDiego Periniが見つけたdoScroll を採用しています。確かに、これでも良いのですが、自分は天の邪鬼なので、HTCファイルでondocumentreadyを監視するというアプローチにしています。上に挙げたイベントの発火順序を調べるページの結果を見ると、IEに関しては、次のようなイベント順位で実行されてます。
- oncontentready /* この時点でDOMのパースが終了 */
- deferred script /* defer指定された外部スクリプトが実行される */
- ondocumentready /* 次にHTCでのこのイベント。oParts.jsではこの時点で初期化。*/
- doScroll /* 次にdoScroll */
- window.onload /* 最後にこれ */
このサイトのように、ソースをハイライト表示するスクリプトなどを使ってる場合は、数ミリ秒でも早くハイライト関数を起動させたいので、ondocumentreadyのタイミングで実行させてます。doScrollのタイミングでも良いんですが、十数ミリ秒程度遅れるんですよねぇ。oncontentreadyが一番早いですが、極々まれにこれが評価されないことがあるので、確実なondocumentreadyにしてます。ondocumentreadyとかoncontentreadyってBehavior絡みでしか使えないのが玉に瑕です。普通のイベントハンドラとして使えるようにしてくれれば良いのに、マイクロソフトさん。
というわけで、ppBlogで使っているJSライブラリ oParts.js での初期化関数は以下のような感じになってます。
oParts.start = function(F){ if(client.Gecko || client.Opera || client.Safari){ document.addEventListener('DOMContentLoaded', F, false); } else if(client.MSIE){ $IEHTC = document.documentElement.addBehavior('js/ie.htc'); } else o(window).on('load', F); };
SafariでもDOMContentLoadedが使えるようになったので記述が少なくて良いですね。IE向けのie.htcファイルの中身は以下のような感じ。
<public:attach event="ondocumentready" onevent="oParts.callee[oParts.callee.length-1](); document.documentElement.removeBehavior($IEHTC); $IEHTC=null;" />
ちなみにイベント発火順位を調べるスクリプトですが、以下のように指定すると、このサイト以外のページも読み込めます。Yahoo!の例を挙げておきます。
http://p2b.jp/demo/events-order.php?site=yahoo.co.jp
余談ですが、jquery-1.2.3のテストをしていて、気になった点がありました。以下のようなスクリプトを書くと、$()関数がwindow.onloadの後にしか実行されません(IE7の場合)。jqueryに関しては素人なので使い方が間違っているのかもしれませんが、非常に簡単な例なので気になります。
<script type="text/javascript"> window.onload = function(){ document.getElementById("test").innerHTML = '<p>window onloaded!</p>'; } $(function(){ alert($("#test").html()); }); </script>
実際の実行サンプル 。FirefoxとIE7で挙動が違います。Firefoxでは意図したように、window.onloadよりも先に$()が評価され、<p>original</p>とアラート表示されますが、IE7ではなぜか、window.onloadに割り当てた関数が先に実行されて、<p>window onloaded!</p>って表示されるんですよねぇ。何でかなぁ。doScroll絡み?
Comments