In most projects there are tons of events that are dispatched, but that have no listeners subscribed to them. This shouldn't be an issue, but it turns out that the Flash Player deals with these events inefficiently. Luckily it's pretty easy to patch this for specific situations.
The code below will run about 5X faster than a standard dispatchEvent call when there is no event listener for the event type.
override public function dispatchEvent(evt:Event):Boolean { if (hasEventListener(evt.type) || evt.bubbles) { return super.dispatchEvent(evt); } return true; }
Note that the actual time difference is fairly minimal (80ms vs 450ms for 100,000 iterations in my tests), so I would only do this in classes that you are going to create a lot of instances of and which will generate a lot of events that may not have listeners.
For example, I used this in GTween, because you could have thousands of tweens active at the same time, each of them dispatch CHANGE events every frame while active, and it's very common to create tweens without a listener for that event.
While I think this will work for all cases, I haven't tested extensively with less common event scenarios. Bubbling events should work, but you won't get a performance increase.
This change also reduces efficiency for events that do have listeners, but it is very minimal (<10%, 505ms vs 545ms for 100k iterations in my tests).


Comments (14)
I think it's even better if we avoid Event object creation in those cases that don't have listeners. However, this is not needed when we reuse the same event instance everytime.
Posted by: Ignacio Alles at December 10, 2008 12:07 PMURL: http://www.mpadvanced.com
I hope Adobe will implement this, next to the removeAllListeners(), removeAllListenersOfType(eventType), getAllListeners() and some others for some more flexibility.
Something else i noticed that's missing, but it's more like a EMCA specs thing: when you pass the method/closure when subscribing to an event, there's actually no way the compiler can check if it is a valid eventhandler (one that accepts a single valid typed argument).
You're stuck with runtime checking. This issue can be broadened into any closure you store in a Function-typed property or variable and call from that lateron (by using the call operator's '()' or apply() or call()).
In these days of typing and Interfaces and all that it feels wrong. I know you can fight it with discipline, but im getting used to the compiler enforcing most of my lazy errors. I would prefer if there was a formular way of describing a required closure signature (like an Interface for Functions). Got any thoughts on that?
Posted by: Macaca at December 10, 2008 12:11 PMURL:
Wouldn't just calling something like this be more efficient in all cases?
Posted by: Matt Rix at December 10, 2008 12:41 PMhasEventListener(Event.CHANGE) && dispatchEvent(new Event(Event.CHANGE));
URL:
Ignacio & Matt - yes, both of those things would make it more efficient, however you start to reach diminishing returns in performance versus code clarity .
Instantiating the Event object has a minimal impact on performance: it only speeds things up a further ~20% (65ms versus 80ms), and requires a lot more complexity.
Using the approach Matt suggested is a lot faster (almost another 5X gain), and definitely might be worth doing in some situations. Note though that while the multiplier is similar, the performance gain is massively diminished (saving 60ms for 100k iterations versus saving 370ms). Again, you have to make a choice of performance versus clarity. My approach is transparent, whereas Matt's suggestion requires a per case decision and implementation (it will break for bubbled events, for example). Mine also requires per class maintenance versus per call (ex. if EventDispatcher was updated to make these approaches unnecessary).
Neither is wrong, you just need to evaluate all the advantages before choosing your tools.
Posted by: Grant Skinner at December 10, 2008 01:12 PMURL: http://gskinner.com/blog/
Yep, that's true, it all depends on what you're trying to do with it and how you want to approach it. I'm thinking that for my approach, I could check for bubbling as well if I thought the event had the potential to be bubbled.
Oh and just in case any of your readers are confused at the '&&' syntax I used, it's functionally equivalent to writing it like this:
Posted by: Matt Rix at December 10, 2008 01:54 PMif(hasEventListener(Event.CHANGE)) dispatchEvent(new Event(Event.CHANGE));
URL:
Also worth noting, this syntax:
if (hasEventListener(Event.CHANGE)) { dispatchEvent(new Event(Event.CHANGE)); }
Runs at exactly the same speed as using &&, and is a much clearer syntax.
Posted by: Grant Skinner at December 10, 2008 01:58 PMURL: http://gskinner.com/blog/
I'm not sure, really, but in my opinion this override is only suitable for non-display objects, as it doesn't consider listeners that link into some ancestor in the event queue. For them you'd check willTrigger() – but I may have missunderstood that.
Posted by: Severin Klaus at December 10, 2008 06:50 PMURL: http://blog.betabong.com
Severin - that's what the check for bubbles is for. There's a chance I may be missing something though.
Posted by: Grant Skinner at December 10, 2008 07:04 PMURL: http://gskinner.com/blog/
do you think doing this test is efficient before adding event Listener like
Posted by: gropapa at December 11, 2008 01:45 AMif(!hasEventListener(Event.COMPLETE))addEventListener(Event.COMPLETE, becauseImFrench)
or is it worthless?
URL:
Event.bubbles only checks wether the Event can bubble. But you can also listen to an event in the capture phase (using useCapture) which is also triggered for events that don't bubble. That's at least how I understand it. But as I said, that's only a potential problem for display object (unfortunately – i mean, I'd like to have this for my own tree type classes, but that's yet another missing feature).
Posted by: Severin Klaus at December 11, 2008 02:20 AMURL: http://blog.betabong.com
Is willTrigger slower than checking hasEventListener & bubbles? If you don't mind, can you explain why you didn't use willTrigger? Thanks.
Posted by: Mark at December 11, 2008 05:58 AMURL:
Great pointer. I was actually wondering about this yesterday given the impact of firing events out in a loop where it could be cases that you don't have listeners. I figured that the internally the EventDispatcher would just pass on the requst, but it sounds like it doesnt.
Posted by: Kenny Bunch at December 11, 2008 03:06 PMURL:
Are you guys monkey patching EventDispatcher with this?
Posted by: Tink at December 12, 2008 03:16 AMURL: http://www.tink.ws/blog
Nice tip - you keep finding these things, amazing :-)
Posted by: Michael Vestergaard at December 12, 2008 06:31 AMURL: http://www.iliketoplay.dk