Triggering Non-existent jQuery Events and Performance - javascript

I have some javascript that registers and triggers custom events in jQuery - what I'm wondering is what kind of performance hit, if any, is taken by triggering an event that has no event handlers bound to it - example:
var someData = ['blah', 'foo', 'bar'];
$('#somediv').trigger('StateChange', [someData]);
In the above (very short) example, there is no $('#someDiv').on('StateChange', ...) event handler, so is it a waste to trigger the event and would I see a significant performance hit if, say, I had 5-10 events trigger on a given element with no handlers bound?

No, for 5-10 objects you won't see a significant performance hit for triggering an event that has no handler.
Keep in mind that the point of an event system is that you don't need to worry about whether or not the object in question has been assigned a handler for the requested behavior. This way you can casually trigger the event without needing any sort of testing.

Related

Event Listeners Efficiency

How do event listeners in any programming language actually work internally?
The point of this post is to get an overall idea of how event listeners in general work. A while back, when I first started playing with Javascript and Html, every time I needed to create a button to perform an action, lets say execute function 'my_func();', I would simply go...
<button onclick="my_func();">Click me</button>
That is just wonderful, a button, staying idle for the majority of the time, except when clicked. Then, it would execute the corresponding function.
Then I came across Event Listeners. Basically, an event listener is a procedure or function in a computer program that waits for an event to occur.
The first thing that came into my mind was the following: When you create an event listener, does that basically just create an infinite loop that checks whether something has been triggered or not? Isn't this inefficient if you have dozens or hundreds of events to listen for? Hundreds of loops checking for a different specific condition every second? Why would you use this instead of the beautiful 'onclick'?
I will proceed to post the answers that I found, (not in StackOverflow, that's why I decided to post it here, so as to enlarge the already vast content of this site). This answer, of all the ones I read, was the one that convinced me the most. However, if you know something that you think would add to the topic, feel free to share your knowledge (the more the better).
The core question was the following: Isn't this inefficient if you have dozens or hundreds of events to listen for?
And the truth is, if that was the case, it would be really inefficient. That is why it doesn't work that way.
The program (in the case of Java), or browser (in the case of Javascript), receives events from the operating system every time something happens — when the mouse is moved, when a key is pressed, when the window is resized, when a timer event expires, and so on. For each of those events, the browser needs to figure out if an event handler needs to be dispatched. For example, on a mouse left button down event, it needs to take the coordinates of the mouse and figure out what elements are underneath it, and then check if there are any event listeners registered for those events, and if so add them to the event queue to be executed the next time the engine becomes free.
Once again, feel free to add information, or correct me if you think there is something wrong or somehow inaccurate.
There's very little difference between running an event handler from onclick and from addEventListener. In both cases, it simply attaches the handler to the DOM element in question. The only significant difference between them is that you can only have one onclick attribute, but every time you call addEventListener() it adds to the list of listeners on that element -- internally there's an array of listeners that addEventListener() pushes onto.
But the way these event handlers are processed is essentially the same. When a click event is sent to an element, the browser looks up its onclick attribute and list of click listeners, and executes all of them. There's no difference in efficiency between them. The only infinite loop is the browser's main event loop, which is processing all events that are received from the OS, finding the appropriate DOM elements, seeing if they have handlers for that event, and calling the handlers.
As what others have said, internally there is no difference between the two. But using the addEventListener() method you can easily attach multiple functions on a single event rather than going through concatenations when you have lots of scripts.
with addEventListener()
Script 1
myEle.addEventLister('click', myFunc);
Script 2
myEle.addEventLister('click', myFunc2);
You see how easy it is to attach functions on an element's event.
using setAttribute()
Script 1
myEle.setAttribute('onclick', myFunc);
Script 2
myEle.setAttribute('onclick', myEle.getAttribute('onclick') + myFunc2);
The extra code is a bit of a hassle
For practical purposes, there is no difference between the 'onclick' and the 'EventListener' attributes. All in all, that's just what they are, attributes that you add or remove from a specific object. As a consequences, since they are attributes, not mere methods, they do not loop themselves, but instead serve as parameters for the "general event loop" that constantly occur in your window. Hence the lack of difference in efficiency.
However, if you have a ton of event listeners, or onclick attributes on a ton of different objects, it may reduce the overall execution speed, as the general loop has to go through more elements to check, for a specific occurred event, if there is anything listening to it; but this happens indistinctelly of how you address your events (with a listener, onclick attributes, etc.)
So, I will conclude by saying that there is no practical difference in the way these event handlers are processed. When a particular event is sent to an element, the browser looks up on its attributes and/or list of listeners related to that particular event, and executes each one of them. There's no difference in efficiency between them. The only infinite loop is the "general window loop" or the main event loop, which is processes all the events that happen, and looks for the appropriate object to check for any handlers related to that event, and should any be found, it calls the function attached to them.

Are JavaScript events always executed even if there is no one listening?

Are events in JavaScript always fired even if there are no listeners attached?
Lets say "mousemove", I move the mouse but there are no listeners in the whole app, will the browser still construct a new Event and fire it, or will it optimize and consider the fact that if there are no event listeners, just ignore the data.
I assume that each browser works differently and I'm assuming they use patterns like observer and what not, but is there a spec around that states how it should be?
Feel free to downvote this if you feel this is not correct but from my understanding and according to the DOM Level 2 Events Spec there is a sense that events are always constructed and executed but listeners need to be there, of course, to actually register them.
The reason I say "there is a sense that events are always constructed and executed" is because the Spec mentions that
This method allows the registration of event listeners on the event
target. If an EventListener is added to an EventTarget while it is
processing an event, it will not be triggered by the current actions
but may be triggered during a later stage of event flow, such as the
bubbling phase. If multiple identical EventListeners are registered on
the same EventTarget with the same parameters the duplicate instances
are discarded. They do not cause the EventListener to be called twice
and since they are discarded they do not need to be removed with the
removeEventListener method.
So if event listeners are dynamically added, there needs to be a way for the the page to know to register and listen to them. How each browser handles this is probably different as #JAAulde mentioned above but I do not think browsers would optimize for the fact that an event listener exists or not or at least nothing drastic.

Real world example where event capturing is necessary / preferred?

The addEventListener DOM method supports a third optional, boolean parameter (useCapture) to indicate whether the function should use event bubbling or event capturing as propagation method. In this article the difference is nicely shown (click on the examples & view code).
From other questions on SO and blog posts, I concluded event bubbling was preferred mostly because IE8- didn't support it.
Suppose I'm only required to support IE9+, in what situation would event capturing be necessary or preferred over event bubbling? In other words, in what situation would it be better to let the events execute on the outermost elements first, and then the innermost elements? I'm looking for a simple, real world example to demonstrate the use of event capturing...
Event capturing used to be the only option outside of the Internet Explorer browser:
One of the major differences of the back then two important browsers was how they handled events. Microsoft worked with the bubbling phase - meaning the event first hit on the target element and then traverse the whole DOM upwards hitting on the parent nodes whereas Netscape did it the exact other way - meaning the event first passes the parent elements and then runs down to the target element - capturing. This caused developers in the early days a lot of trouble and the W3C finally specified an approach where both kind of works and can be used at free will.
Event capturing is useful in event delegation when bubbling is not supported. For example:
Some events, such as focus, don't bubble but can be captured.
The inline handler on the target element triggers before capture handlers for the target element.
Many newly specified events in the web platform (such as the media events) do not bubble, which is a problem for frameworks like Ember that rely on event delegation. However, the capture API, which was added in IE9, is invoked properly for all events, and does not require a normalization layer. Not only would supporting the capture API allow us to drop the jQuery dependency, but it would allow us to properly handle these non-bubbling events. This would allow you to use events like playing in your components without having to manually set up event listeners.
Custom events and bubbling have the following issues:
Currently, Ember relies on jQuery for event handling, doing so comes with several costs:
jQuery silently changes inline handlers to bubble handlers.
This changes expected invocation order
This can cause automated tests to fail
Events triggered via jQuery.trigger trigger handlers in a different order than events triggered by a user.
This changes expected invocation order
This leads to difficult to reason about and debug aberrations in behavior
This often causes automated tests to fail
Events must flow down and bubble back up through the entire DOM before being detected by the Ember application, and then must undergo an expensive delegation process that is effectively re-bubbling to find the right handler.
Handlers attached directly within components or by non-ember plugins take precedent over handlers attached by Ember, whether this was desired or not.
This causes component handlers to have far-reaching side-effects
This leads to difficult to reason about and debug aberrations in behavior
This often causes automated tests to fail
A media player focus=>play preprocess/postprocess event flow would be a simple use case.
The mechanics of the capturing phase make it ideal for preparing or preventing behavior that will later be applied by event delegation during the bubbling phase. And that’s how we’re going to use it here—to initialize the sortable in response to a mouse click, but just before the event starts bubbling and other handlers have a chance to deal with it.
To make use of capturing, we have to go down to the metal. jQuery’s event methods only work for bubbling and don’t let us tap into the capturing phase. The capturing handler looks like:
document.addEventListener("mousedown", function(event) {
if ($(event.target).closest(".sortable_handle").length) {
$("article.todolist, section.todolists").sortable();
}
}, true);
References
Domina Github Repo: Readme - Event Propagation
EmberJS RFC: Capture Based Eventing
EmberJS RFC: Internet Explorer
MDN: Event.eventPhase
Using event capturing to improve Basecamp page load times – Signal v. Noise
Bubbling, foreign events and Firefox: Index
Event capture and bubbling

Does having a large number of event handlers degrade performace?

I have a page with some 30+ event handlers.
Similar to this:
$section.on("click", "a.unselect-all", function () {
var $s = $(this).siblings("select");
$s.find("option").removeAttr("selected");
$s.val("");
});
The page itself is not all that large.
But I feel that it's response time has become more sluggish with more event handlers.
First off, here's a similar question/answer with some pertinent info to understanding this issue: Should all jquery events be bound to $(document)?.
Here are some notes on large numbers of event handlers and performance:
30+ is NOT a large number of event handlers. In most cases, you shouldn't have to worry about 30+ event handlers at all (see possible exception below if you have nasty selectors).
If event handlers are attached directly to the intended object (the most efficient way for them to be processed at the actual event time), you will maximize your run-time performance.
If you are using delegated event handling, then event handlers should be placed on a parent that is as close as possible to the actual object receiving the event. Putting all delegated event handlers on a top level object like document or document.body is generally a bad idea because that makes the code have to look at more selectors for every event than if the event handlers are closer to the actual object that triggers the event thus avoiding evaluating most of the selectors for most events.
If you are using delegated event handling, then the performance of the secondary selector (the 2nd argument to .on()) is important. If this is a complicated selector that is not fast to evaluate and you have a lot of these all attached to the same object for the same event, you could start to see some performance degradation. How much performance degradation will depend upon the exact circumstances.
So, the worst case is if you have a lot of delegated event handlers all attached to the same object that all have a complicated secondary selector. This is the worst case because the event will have to bubble up to this parent object and then jQuery will have to go through every one of the delegated events for this particular event and it will have to evaluate the secondary selector argument to see if it matches the target object. If you have a lot of these delegated event handlers on the same object and you the secondary selector is somewhat complicated, it's possible that the time to process all this could start to be noticeable.
As with any performance issue, if this is really important to you, then you need to do your own performance testing. Install 30 delegated 'click' handlers with secondary selectors like you will be using to the document object in a sample page and try it. See if you can see any performance degradation at all between the click and the response to the click. Try it with 100 event handlers, 1000 event handlers, etc... until you see where it becomes noticeable.

How does event handling work internally within JavaScript?

Specifically Spidermonkey.
I know you write functions and attach them to events to handle them.
Where is the onClick handler defined and how does the JS engine know to fire onClick events when the user clicks?
Any keywords, design patterns, links, etc are appreciated.
UPDATE
Aggregating links I find useful here:
http://www.w3.org/TR/DOM-Level-2-Events/events.html
https://github.com/joyent/node/blob/master/src/node_events.cc
http://mxr.mozilla.org/mozilla/source/dom/src/events/nsJSEventListener.cpp
SpiderMonkey itself doesn't have anything involving event handling. Events are purely a DOM thing.
The click event is fired by the browser code (the thing embedding SpiderMonkey), not by SpiderMonkey itself. See http://hg.mozilla.org/mozilla-central/file/e60b8be7a97b/content/events/src/nsEventStateManager.cpp for the code that's responsible for dispatching things like click.
The browser is also what defines setter methods that take an assignment to the onclick property and turn it into an event listener registration. See http://hg.mozilla.org/mozilla-central/file/e60b8be7a97b/dom/base/nsDOMClassInfo.cpp#l7624 which is called from nsEventReceiverSH::SetProperty and handles properties whose name (id in this code) passes the IsEventName test.
When event listeners are registered and an event is fired, the event dispatcher manages calls to the listeners; the nsJSEventListener link you found is the glue that converts a C++ HandleEvent call into a call to a JS function.
So in your case, you want some sort of registration/unregistration mechanism for listeners and then your implementation will fire events and dispatch them to listeners. How you do this last part is pretty open-ended; the Gecko implementation has a lot of constraints due to needing to implement the DOM Events specification, but you should be able to do something much simpler.
HTML uses sink/bubble event propagation schema: http://catcode.com/domcontent/events/capture.html
There are "physical" events (mouse, keyboard) and logical/synthesized ones (focus,click, value_changed, etc.)
onClick is a logical event - generated as a result of mouse, touch and/or keyboard events.
Mouse (or finger touch) originated click event is a result of mouse down, move and up events. Note that mouse down, move and up are sinking/bubbling events. Target element(s) in these "primordial" events will be the target(or source) of the click event. If mouse-down/up events have different targets (DOM element) then their common parent is used.
Sequence of mouse down, move and up events may produce different logical events: click, swipe/scroll, etc.
I believe this is a full list of basic concepts.

Categories