I am building a library which augments the standard JS input events.
This means firing off a great many events for multiple touches at input sampling rate (60Hz) in the browsers of ARM devices.
I have looked at this jsperf and it produces about 250,000 ops/sec on my 1.7Ghz Sandy Bridge i5 and I will test my iPhone5 and Nexus7 on there shortly.
My question is will an unlistened-to event be processed quickly?
Also is there a way to skip processing for generating an event if I know the event is not being listened to?
I think that jsperf muddies the waters when it comes to dispatching and handling events because event listeners are also added and removed every test loop iteration. It sounds like your use-cases have high-frequencies of dispatching and handling events, but comparatively low demands for adding and removing event handlers.
I put together a jsperf that focuses on wrapping a native event with a custom event and then disatches the custom event. The test scenarios are based on:
Presence or absence of a listener for the custom event
Immediate vs lazy initialization of data associated with the custom event
The impact of the above factors when dealig with "light" vs "heavy" intitialization demands
To test the "heavy" vs "light" initialization demands, each custom event creates an array of either 10 or 1000 random numbers.
Regarding lazy initialization of custom event data:
When a listener was present, the lazily init'd event was usually a bit slower. For "light" data it was sometimes as low as 0.8x the speed of the immediately init'd event.
Without a listener, the lazily init'd data was usually faster for both "light" and "heavy" data. For "heavy" data, it was generally 2x-10x faster.
My question is will an unlistened-to event be processed quickly?
In everything I've seen, an unlistened to event is always processed faster than an event that has an associated handler. But, I think this will only have a large impact if the event handlers, themselves, are rather slow and costly. Also, the higher the cost of creating the custom event the less this will matter if the custom event is created either way.
Also is there a way to skip processing for generating an event if I know the event is not being listened to?
Two things come to mind:
Expose the knowledge of whether the event is being listened to or not to the process that generates and dispatches the event, and then have that process skip creating the event if it knows nothing is listening.
Sounds like the code that generates the custom event will, at some point or another, listen for a native event and then create a custom event(s) based on the native event. In this scenario, you could ignore the native event until an event listener for your custom event has been added, and then ignore the native event again when all listeners for the custom event have been removed.
Related
I am writing a custom element and I want to periodically emit an event.
Emitting the event requires some work, so I was thinking maybe I can be lazy and only emit the event (and do the work) if there is a listener.
Is it possible to detect that someone is listening to an event (non bubbling)?
And in that case start emitting, until the listener is removed.
Or will the Javascript runtime be smart enough to not run the interval (where the only side effect is creating an event) when there is no listener?
With Javascript standard events, it appears you can't (unless you override the registration mechanism).
But with custom registering and callback methods, you can achieve this by implementing the Observer pattern.
Anyway, it you're lazy maybe it's easier to send useless events :-)
I am using jQuery quite heavily in a ASP.NET WebForms application to handle anything client-side that isn't application-critical (eg. on the fly validation, animations, general fluff and pretty stuff).
Within this solution, I am using update panels, so the main page rarely gets refreshed. As such, event listeners can get bound on each asynchronous postback.
With this in mind (or in any other typical circumstances), is there any advantages to using .off to remove event listeners on elements that I know are not going to be active at that time?
Is the standard browser going to suffer much, if any, performance degradation if I leave the event listeners active, or will it only be noticeable at absolute extremes?
Should I just unbind (.off) when I bind (.on) at high-level elements such as body?
What is the best way to handle (if required) unused event listeners in a scenario where they are being bound and unbound multiple times over the life-cycle of a single web-page?
If you have any tests that show if browsers slow down with numerous event listeners, please let me know. Proven numbers would be perfect if anyone has them.
Leaving inactive event listeners will definitely show negative impact on performance. It is definitely a better practice to off unnecessary event listeners.
I would also suggest you to use scope while binding event listeners like
$(".demo").on("click.test", function(){ ... });
Here I have scoped the click event with test so that when I do
$(".demo").off("click.test");
any other demo class having an on click listener will not get switched off.
I have a general question about javascript (jQuery) events/listeners.
Is there any limit for the number of click listener without getting performance problems?
In terms of performance, the number of elements the event is bound to is where you'd see any issues.
Here is a jsperf test. You'll see that binding to many elements is much slower, even though only one event is being bound in each case.
The 3rd test in the jsperf shows how you'd bind the event to a parent element and use delegation to listen for the elements you want. (In this case .many)
n.b. The test shows that the 3rd option is the fastest, but that's because it's targeting the element with an id and not a class.
Update: Here's another perf test showing 3 events bound to an id vs one event bound using a class
Though this is an old question, I do not feel that it's completely answered yet.
As atmd pointed out: It's already important where you're adding the event handlers to.
But the original question seems to be more concerned about the performance impact of triggering those event handlers (e.g. click or scroll events).
And yes, adding additional event handlers to an element DOES decrease performance.
Here is a performance comparison to test the following cases:
https://jsbench.me/ztknuth40j/1
The results
One <div> has 10 click handlers, and the click event is triggered by jQuery.
→ 72.000 clicks/sec
One <div> has 100 click handlers, and the click event is triggered by jQuery.
→ 59.000 clicks/sec ~ 19% slower than first case
This shows, that additional event handlers can slow down the execution
One <div> has 10 click handlers, and the click event is triggered by plain JS.
→ 84.000 clicks/sec ~ 6% faster than the first case
Using plain JS is a little bit faster than using jQuery
One <div> has 100 click handlers, and the click event is triggered by plain JS.
→ 14.000 clicks/sec ~ 77% slower than second case
This is interesting: When using native events, the number of listeners seems to degrade the performance faster than using jQuery.
(Those results vary on every run and depend largely on your hardware and browser)
Keep in mind that those tests are done with an empty function. When adding a real function that performs some additional tasks, the performance will slow down even further.
Here is a second test that changes the contents of a div on each click:
https://jsbench.me/ztknuth40j/2
Is it slow?
On the other hand: Even 100 operations per second are super fast (it means, that every event handler is executed 100 times in a single second) and no user will notice the delay.
I think you will not run into problems with user-action events like click or mouseenter handlers, but need to watch out when using events that fire rapidly, like scroll or mouseover.
Also, as computers get faster and browsers apply more and more optimizations, there is no hard limit for how many event handlers are "too much". It not only depends on the function that's called and the event that's observed but also on the device and browser of the user.
Problem: I need to bind any number of event handlers to any number of elements (DOM nodes, window, document) at dynamically runtime and I need to be able to update event binding for dynamically created (or destroyed) nodes during the lifetime of my page. There are three options that I can see for tackling this problem:
I) Event delegation on window
II) Direct event binding on each node
III) Event delegation on common ancestors (which would be unknown until runtime and would potentially need to be recalculated when the DOM is altered)
What is the most efficient way of doing this?
A little context
I am working on a set of pages that need analytics tracking for user events (clicks, scrolling, etc.) and I want to be able to easily configure these event handlers across a bunch of pages without needing to write a script to handle the event binding for each instance. Moreover, because I may have the need to track new events in the future, or to track events on elements that are dynamically added to/removed from the page, I need to be able to account for changes in the DOM that occur during the lifetime of the page.
As an example of what I'm currently considering, I would like to create a function that accepts a config object that allows the programmer to specify default handlers for each event, and allow them to override them for specific elements:
Analytics.init({
// default handlers for each event type
defaultHandlers: {
"click": function(e) { ... },
"focus": function(e) { ... }
},
// elements to listen to
targetElements: {
// it should work with non-DOM nodes like 'window' and 'document'
window: {
// events for which the default handlers should be called
useDefaultHandlers: ['click'],
// custom handler
"scroll": function(e) { ... }
},
// it should work with CSS selectors
"#someId": {
useDefaultHandlers: ['click', 'focus'],
"blur": function(e) { ... }
}
}
});
Sources
SO: Should all jQuery events be bound to document?
SO: How to find the nearest common ancestors of two or more nodes
jQuery docs: $.fn.on()
I usually delegate events on the document.documentElement object because:
It represents the <html> element on the page, which holds everything which holds all the HTML tags the user can interact with.
It is available for use the moment JavaScript starts executing, negating the need for a window load or DOM ready event handler
You can still capture "scroll" events
As for the efficiency of event delegation, the more nodes the event must bubble up the longer it takes, however we're talking ~1 to 2 ms of time difference -- maybe. It's imperceptible to the user. It's usually the processing of a DOM event that introduces a performance penalty, not the bubbling of the event from one node to another.
I've found the following things negatively affect JavaScript performance in general:
The more nodes you have in the document tree, the more time consuming it is for the browser to manipulate it.
The greater the number of event handlers on the page the more JavaScript slows down, though you would need 100s of handlers to really see a difference.
Mainly, #1 has the biggest impact. I think trying to eek out a performance boost in event handling is a premature optimization in most cases. The only case I see for optimizing event handling code is when you have an event that fires multiple times per second (e.g. "scroll" and "mousemove" events). The added benefit of event delegation is that you don't have to clean up event handlers on DOM nodes that will become detached from the document tree, allowing the browser to garbage collect that memory.
(From the comments below) wvandell said:
The performance costs of event delegation have little to do with the actual 'bubbling' of events ... there is a performance hit incurred when delegating many selectors to a single parent.
This is true, however let's think about the perceived performance. Delegating many click events won't be noticeable to the user. If you delegate an event like scroll or mousemove, which can fire upwards of 50 times per second (leaving 20 ms to process the event) then the user can perceive a performance issue. This comes back to my argument against premature optimizations of event handler code.
Many click events can be delegated with no problem on a common ancestor, such as document.documentElement. Would I delegate a "mousemove" event there? Maybe. It depends on what else is going on and if that delegated "mousemove" event feels responsive enough.
If I have an element (html) nested in another element and both of them have a click handler attached, clicking the inner element executes its click handler and then bubbles up to the parent and executes its click handler. That's how I understand it.
Do events bubble up the DOM tree if there are no events attached that are the same and if so, is it worth putting a event.stopPropagation() at the end of every handler to stop this and speed things up?
events almost always bubble up unless event.cancelBubble=true is set or event.stopPropagation() is used. You are only aware of it, though, when one of your event
handlers gets tripped.
See http://en.wikipedia.org/wiki/DOM_events for a list of events which bubble. (Note: in the table of HTML events, cancelable refers to the effectiveness of event.preventDefault() or return false to cancel the default action, not bubbling)
Also see http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow, in particular 1.2.1 Basic Flow to understand the capture phase and bubbling phase of event propagation.
EDIT
http://mark-story.com/posts/view/speed-up-javascript-event-handling-with-event-delegation-and-bubbling suggests there is a performance gain by stopping propagation but provides no data.
http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/a9af0aa4216a8046 suggests that browsers should be optimized for bubbling behaviour and says there should be no significant performance difference. Again no data.
http://developer.yahoo.com/performance/rules.html#events provides a good technique for improving event-handling performance, but doesn't directly talk about stopPropagation performance.
Ultimately, you'd have to profile the difference to get a good idea of the benefits on your site.
I suppose this behavior is already well optimized by browsers, so you won't be able to catch significant performance boost when stopping propagations (except, perhaps, for really-really complex nested DOM structures). If you are worried by performance and deal with lots of events, you may be interested in event delegation instead.
Also, you should remember your code should stay readable and self-explainable. stopPropagation() is a method used for certain purpose, so using it in every method could be really confusing.