Cute solutions and something else...

Order of Events

Published Tuesday, February 21, 2006 by Роман Рахман.

I use prototype.js as many other developers in the world do.
I guess one of the most useful objects in this framework is Event. It’s a really simple way for observing events without any thoughts about difference between Event Model in Internet Explorer and "Truth Nice Browsers" (like Firefox).

You can just write:
Event.observe(window, "load", myLoadHandler);

Dead easy!

But there’s a thing which drives me mad sometimes. It’s the order of event firing. And it’s not a problem of Prototype framework, but problem of Internet Explorer Event Model.

Just a small example (don't forget to include prototype.js):
var count = 2;   
for(var i= 1 ; i<=count; i++) {   
    var handler = new Function('alert('  + i +  ')');   
    Event.observe( window ,  'load' , handler);  
}   

What order of alerts do you see in Firefox? Bingo! 1, 2
In Internet Explorer? Huh, 2, 1

Set count = 3 and repeat.
Firefox? Surely 1, 2, 3
IE? 3, 2, 1? Sorry, actually not! 2, 3, 1. Why? Don’t ask me, please.

Interested? Let’s continue with count = 4
Firefox: 1, 2, 3, 4. If we had got another result I would have eaten my VisiBone
Javascript card

And extra-weird in IE: 2, 4, 3, 1

What’s the method of events ordering that IE uses? Neither FIFO (like Firefox), nor LIFO.
This software makes me more and more unhappy.

BTW, I checked this code in IE 6.0 (Window 2000) and IE 7 b2 (Windows XP).
As you can suspect, the result was the same.

Why did I start from prototype and how is it related to the ugly IE Event Model?

I think it’d be very nice if Sam Stephenson included algorithm which will correct this IE bug to prototype Event object I mean Event.observe() shouldn’t add event handler directly by calling .addEventListener() or .attachEvent() but store handlers in internal hash and call them in right order.

8 Responses to “Order of Events”

  1. Anonymous Anonymous 

    Roman, I found your post in the middle of Dustin Diaz "Forget About addEvent()" column. And found it intersting immediately...

    I found it too late, because I already submitted a bug report to Yahoo about they also using attachEvent and then loose the oreder of event firing.

    I am glad somebody else is looking at this problem because I believe is a very serious matter in building Webkits like Google, Yahoo and others are doing.

    I haven't tryed Prototype event handling yet, but if you say it uses attachEvent I already know the result.
    Event randomly ordered (!?!).

    I have been looking to PPK, Scot Andrews and Dean Edwards addEvent() talks and the addEvent recoding but the actual solution, also if reordering events works well, fails if you have different frames with events in the same document so we gain something but loose something else,

    I am also looking to a final solution to this debate and if I have time next week I will dig again in the code and see what it will end up with a patch I had for the iframes problem in Dean Edwards attachEvent which passed unnoticed but had it working once...

    Well if you are available and would like to discuss this and you have test cases for the ordering or the multiframes environment I would like to test them on
    my events environment and share my thought.

    Diego

  2. Anonymous Anonymous 

    Thanx Diego for your comment.

    BTW I'm researching Dojo Toolkit now (http://dojotoolkit.org/) and there isn't this problem here.

    You can write
    dojo.event.connect(window, 'onload', handler);
    and have the same order in IE and FF

  3. Anonymous Anonymous 

    Roman,
    you may be interested into read this blog about "Cross-Window" event:

    http://www.outofhanwell.com/blog/

    the test case you will find there will help spot the problem with IE and IFRAMES I talked above.

    Dojo also suffer from this problem as many other event wrappers. Prototype (up to 1.4) doesn not have this problem since they use attachEvent() but then loose the event reordering as do YUI.

    Diego

  4. Anonymous Anonymous 

    I've also noticed this and fixed the calling order with my addEvent (though it uses attachEvent):

    http://en.design-noir.de/webdev/JS/addEvent/

    Dao

  5. Anonymous Anonymous 

    Dao,
    the event reordering is just one part of the problem, but I see that you have a nice solution, however it will not be adequate if one need to add/remove events continuously since your array of listeners will grow continuously, and the loops will take forever to go through all the empty elements of these array. The "delete" part you have in your code is not enough for these kind of situations.

    However for the majority of the case your addEvent will be more than sufficient since you correct both the order and the scope for the "this" keyword.

    There are also good news on Dean site for the "onload" problem. A new property appeared for IE that will come handy, it is the "document.activeElement" and related events.

    Diego

  6. Anonymous Anonymous 

    Diego, thanks for taking a look at my solution. The problem is that I cannot simply cut the array, because it would break the Event._callListeners loop in this case:

    function x() { removeEvent (window, 'load', x) }
    function y() { /*whatever*/ }
    addEvent (window, 'load', x);
    addEvent (window, 'load', y);


    Simplified, this is what would happen:

    // add the listeners
    var stack = [x,y]

    // enter the loop
    var i = 0

    // access listener 0
    typeof stack[i] // "function"

    // remove listener 0
    stack.splice(0,1) // stack: [y]

    // continue
    i++

    // access listener 1
    typeof stack[i] // "undefined"


    If you know a way to handle this, let me know. :)

  7. Anonymous Anonymous 

    Okay, I think I got it ... new version online. I just hope there are no cases I didn't think of.

    Thanks again for your feedback.

  8. Anonymous Anonymous 

    Dao,
    I haven't got the time to look againg in to your code however here is my tip or at least how I do it:

    - use a Hash function to add and remove objects and mantain its length by incrementing/decrementing.

    Objects properties can be removed with delete, arrays items cannot be removed the same way.

    Diego

Leave a Reply




About me

  • I'm Роман Рахман
  • From Донецк, Ukraine
  • My profile

Links