IEでイベントの順番がおかしくなる訳
ページ表示を待って処理を実施したいときに Prototype の Event.observe(window, 'load', function(){...}); をよく使います。 これを複数回使った場合、登録された順に実行される… はずだったのですが、IE では順番が狂うみたい。 んでさっそく、テストページを作ってみました。
実行する JavaScript は以下のように単純なものです。
Event.observe(window, 'load', function(){ alert(1); }); Event.observe(window, 'load', function(){ alert(2); });
実行結果
以下は定義した順 (1,2) で表示されたもの。
で、以下が定義した逆順 (2,1) で表示されたもの。
- IE8 Beta
- IE7
- IE6 SP2
実行結果はやはりといいますか、IE だけが変でした。 標準準拠(xhtml)モード、互換(HTML)モードでは結果はかわりませんでした。
IE だけ結果が変な理由
Prototype 1.6.0.2 の該当部分のコードは以下のようになっています。 まぁ、一般的な記述でしょう。
if (element.addEventListener) { element.addEventListener(name, wrapper, false); } else { element.attachEvent("on" + name, wrapper); }
IE では addEventListener が使えなくて、かわりに attachEvent があるのですが、この実装が問題。 登録した順には実行してず、逆順ですらなく… なんと順不同で呼び出してくれちゃう模様。 なんじゃそりゃ。
この問題、IE8βでも直っていなかったのが、個人的にはプチショックです。 DOM に準拠して、そろそろ addEventListener が実装されてると予想していたから。 それなら attachEvent がこれまで順不同だったので、せめて登録順の実装に換えといてくれよぉ、とか呟いてみたり。
とりあえずの逃げ
自分的に最も困るのが、window の onLoad イベントで、こればかりは登録順であって欲しい。 他のは順不同でも呼ばれないわけじゃないから、まぁなんとかなります。
具体的には、自分の Web で使用させてもらっている GlassBox というライブラリに非常に癖がありまして… 初期化の順番を違えると表示がうまくできないんだ、これが。
で、クイックハックといいますか、いちばんベースのライブラリに以下のコードを追加しています。
jp.rinco.observeList = []; Event.observe(window, 'load', function(){ jp.rinco.observeList.each(function(f){ if (f && f instanceof Function) f(); }); });
利用するほうでは、以下のように記載します。 将来的に廃止できることを期待して、条件判断かませています。
if (jp.rinco.observeList) jp.rinco.observeList.push(myInit); else Event.observe(window, 'load', myInit);
やってることは単純で、自分で関数リストを管理して、順に実行しちゃう訳ですね。 単なる配列ですから、処理の最初に放り込んだり自由にできます。 今のところ特にシビアな処理は呼ばないので、エラーチェックはサボっています。