Assuming I have this code, button with inline onclick event:
<button onclick='..js stuff..'>mybutton</button>
I have this button created multiple times because of server-side loop.
Or I would be better giving a class to these buttons, and just do (using jQuery):
$(".button-class").on('click',function(){..});
What is better in terms of performance?
My questions are-
In the inline onclick, does it creates a handler for each button?
In jQuery event binding, does the handler is created only once, and is binded for each button, or, here as well, the handler is created multiple times?
I guess that these are the factors which affect any performance difference. Perhaps the only downside for .on(..) is that I have to do DOM search by class name. (?)
The answer is: it doesn't matter.
Use the latter (jQuery binding) because it moves the code away from the DOM and makes it easier to work with.
With the inline attribute a different handler is theoretically added for each event; each attribute implicitly creates a new callback/function1 that wraps the supplied code. This handler will be replaced if the attribute (or corresponding DOM property) is assigned a different value later. In the case when all the event handlers have been created this is the "worst" approach in terms of book-keeping.
With the jQuery (addEventListener) version the same function callback is added for all the matching elements. Multiple event handlers for the same element/event may be added; care may be required to avoid unintentional repeated-binding.
Furthermore, with delegated events jQuery could avoid binding to each element separately (ie. it only binds one event handler further up the propagation chain). Depending on how many elements are to have events "attached", this could result in a significant decrease of actual events listened to while still only using a single event handler function.
The chance of their being an actual real-world performance difference between the approaches is slim-to-none, degenerate cases aside. Use the form that is most clear/extensible/maintainable which, IMOHO, is rarely the event properties; especially when embedded directly into HTML attributes. (One issue with the inline attribute form is that it cannot bind to an appropriate closure context and so it must use - ick! - global context in many cases.)
1 Browsers first only had inline events (almost exclusively specified in HTML attributes) and are well-optimized for this case. The actual event handler function is only created on demand. Consider the case of <button onclick="alert(">Hi!</button>, where the "onclick" contains a syntax error in the inline JavaScript. A modern browser will only parse the JS (and thus only create the actual handler function) when the the button is clicked or the .onclick property is read.
Using onclick is frowned upon and considered bad form, you should instead be using element.on('click') with jQuery or ng-click in Angular.js.
They both result in the same number of listeners, and basically the same performance.
The counter part using on.event is: if you reload Or rerender the objects using akax you need to instanciate the on.event again, it creates more code and thats more complicated.
Related
Let's say I have bunch of click events. Also one/few of them is for document object.
Which one is better for performance? Click event for each element or :
document.addEventListener('click', (e)=>{
if(e.target == firstObject){ firstFunction(e) }
if(e.target == secondObject){ secondFunction(e) }
if(e.target == ThirdObject){ thirdFunction(e) }
})
Neither is "better." They each have their place in your toolkit.
A single delegated handler is more complex in that you have to do the kind of dispatch you're doing in your example (often using closest or matches), but has the advantage that if you're adding/removing elements you want to act on, you don't have to juggle event handlers.
Directly-assigned handlers are simpler (at least on elements that aren't added/removed), can prevent propagation, and let you keep your code more modular, more in keeping with the single responsibility principle.
Use the one that makes the most sense in a given context.
I think event listener for each element is better if possible, and makes sense in terms of code quality. There are some cases though where a document event listener will be needed ( for example to emulate a click outside behaviour)
That being said here are some of reasons that makes event listener for each element a better solution
event propagation is handled for you by the browser, if you decide to have only one event handler for the whole document, and u want to have event listeners for elements that are contained in each other, then you will need to handle propagation your self. That is to say you need to handle the order in which functions run yourself, and then you will have some either complex generic solution, or a specific imperative verbose code with a lot of if else statements.
Easier to read code, this is even more true for recent frameworks for web like react, angular, etc..., so for example assume you want to have a listener for clicks on the document, where that code should reside, in which file, and which component should own the code.
Removal of event listeners is handled for you by the browser apis, the browser gives you a way to remove event listeners. If you decide to go with a global event listener then you should handle removing event listeners yourself.
Your code will be hard to refactor and easier to break later, because you are coupling your document (or container ) event listener to your components internals. That is if you decide to change the structure of these components later, your document based event listener will probably break. This will depend a lot on how you identify the target of clicks, for example if you were identifying them by class names or other attributes, then these attributes might change later for reasons like styling.
and if you depend on ids for example you might eventually have unexpected results. because what happens for example if you added a listener for an element that has id, removed that element, and then later added another element with same id.
You miss on the development tooling provided for you by browsers, browsers can show you attached listeners for elements, with a document based event listener you wont be able to do that
It's better if you add one by one, because then you can remove event whenever it finish. Moreover you have more control about this event.
The pagination controls on a page I am working on were being bound conditionally on there being more than 1 page. I don't like to see the following code in my projects,
if (pages > 1) {
$('.some_class').bind('event', function() {});
}
because I feel it represents a disorganized coding style. I would put it on the same level as sprinkling return statements here and there rather than using control. I feel like binding events to globally available objects has no place in the local scope of a function call. So what I usually do is make two javascript files, for example: pagination.js and pagination-controls.js. In the one I have logic about building the html and displaying the the pagination controls. In the other I have statements like the following:
$(document).on('click', '.pagination .next', function() {});
Which fires regardless of whether there is a $('.pagination .next') element anywhere on the page. I like the way that feels: the website has behaviours and it only knows about ids and classes, not about instance variables in some local scope somewhere.
EDIT: this is definitely bad practice, as mentioned below. However:
As of jQuery 1.7, the .on() method is the preferred method for
attaching event handlers to a document.
and the discussion on direct and delegated events is relevant. In particular I think the following describes my usage:
By picking an element that is guaranteed to be present at the time the
delegated event handler is attached, you can use delegated events to
avoid the need to frequently attach and remove event handlers. This
element could be the container element of a view in a
Model-View-Controller design, for example, or document if the event
handler wants to monitor all bubbling events in the document.
EDIT: So I guess now I'm wondering "is it bad to prefer binding behaviours to parent elements unconditionally over binding based on logic?" That's perhaps just a question of style, and my original question has been answered so I think I will accept the answer.
Yes, this is causing significant unnecessary overhead, and it is a "bad practice".
Binding your event handling to the top-level document object means that every single click that occurs on any element anywhere in your page will bubble up to the document object, where the event's target is checked to see if it matches .pagination .next.
In fact, the documentation itself recommends against your usage:
Attaching many delegated event handlers near the top of the document tree can degrade performance. Each time the event occurs, jQuery must compare all selectors of all attached events of that type to every element in the path from the event target up to the top of the document. For best performance, attach delegated events at a document location as close as possible to the target elements. Avoid excessive use of document or document.body for delegated events on large documents.
So, you're misusing on. It's for binding directly to elements or to parent elements which may have dynamically created children, and you are meant to bind to the closest possible parent element. Binding to the document is certainly not meant to be the only way you handle events in your page.
Is onclick in HTML identical to .click() in jQuery?
Obviously they are identical from a usability standpoint, but I am curious how the browser handles them.
jQuery attaches events using JavaScript behind the scenes.
An important difference is that jQuery allows multiple events to be bound using click(), where as you can only attach one handler using onclick. This is because jQuery uses either addEventListener or attachEvent behind the scenes, as opposed to binding to .onclick directly.
Furthermore, attaching handlers via JavaScript (using jQuery or not) promotes unobtrusive JavaScript (i.e. not mixing JavaScript and HTML), which is a good thing.
No it's not the same. OnClick sets a property of a DOM element, where .click() adds an eventListener.
The differnce between them is that every DOM element can only have on property of a type at once. So if you use onClick= twice on an element, only last added will win, the first will be overwritten.
This will always alert 2, cause the first attachment will be overwritten:
myDiv.onclick = function(){alert('1')}
myDiv.onclick = function(){alert('2')}
Using .click() or .addEventListener('click', myFunction), you can add as many functions as you want. So the following will alert 1 and 2:
myDiv.click(function(){alert('1')})
myDiv.click(function(){alert('2')})
The differnt between jquerys .click() and .addEventListener() is, that the jquery solution works in all browser, cause IE<=8 has a different syntax (attchEvent). And that you can unbind all click handlers in once. The normal JavaScript solution can only detach the passed function not all of them.
(Noting that jQuery is a JavaScript library and so can't do anything that you couldn't do in JavaScript yourself if you had the time...)
The jQuery .click() method is different to onclick in a few key ways. In no particular order:
jQuery endeavours to normalise the event object so that you don't have to worry about the (mostly) minor differences between browsers
jQuery binds events with .addEventListener() or .attachEvent() depending on what your browser supports, so, again, you don't have to worry about the difference
jQuery guarantees that where multiple handlers have been bound for the same element and event they will be run in the order they were attached (noting that using .onclick you can only bind one handler anyway, but with .addEventListener() and .attachEvent() you can bind multiple handlers)
if you use jQuery's .on() or .delegate() (or the deprecated .live()) to attach events, rather than shortcut methods like .click(), it is easy to setup event delegation
Behind the scenes all the standard browser events are still happening, but jQuery provides a wrapper for them to make all of the above happen. Of course there are some other differences, but I see the above as the most important.
Obviously they are identical from a usability standpoint
No they're not. It would be much more accurate to say that jQuery's events are (almost) the same as .addEventListener() or .attachEvent() in how you use them, but even then as detailed above jQuery gives you an extra level of abstraction to save you having to code it all yourself.
the .click() even in JQuery is not the same. It is a piece of codes on top of the onclick in html. JQuery allows to bind methods to a event using this layer on top of the normal html events.
You can change/override .click() to adapt your needs. For instance when using a mobile browser or pda etc.
I am in the process of creating a huge web application, with a JavaScript based UI, and many events generated continuously.
To avoid bad performance due to the huge amount of the event listeners needed, I of course opted to use a single event listener which will catch all the events generated from the children elements (event bubbling).
The problem is, this application is designed in such a way that one or more modules can be loaded into the main JavaScript library I'm coding (which is responsible for controlling the UI and every other aspect of the program). Of course every module should be completely independent from each other, so you can choose which methods to load, without affecting the general functionality of the library, only adding or removing features.
Since every module can operate in different DOM elements, I need to have at least a single event listener for each module, since two modules can listen for events generated by html elements placed in different DOM branches.
http://jsfiddle.net/YRejF/2/
In this fiddle for example, the first button will let the first paragraph trigger an event, and its parent will catch it. The second button will let the second paragraph fire the event, but the div listening for the same event won't catch it, because it's not fired from one of its sons.
So my question is: is it possible to have a single event listener, able to listen also to events triggered from elements that are not its sons (elements placed everywhere on the page)?
I was thinking about having a js object, or a dom node, which store the data of the element which triggered the event, and the event itself, then a general event will be fired on the global event listener (no matter where it's placed in the dom), and it will then read the data to discover which element generated which event, and act accordingly.
Any help or suggestion about better ways of achieving this?
jQuery has a special binder for this kind of cases: live(). It let's all events bubble to the document and then handles them accordingly. However, if you use div or other containers for different panels etc, maybe using delegate() makes more sense. Don't worry too much about the number of bound elements. Believe me, it will run as well with 50 binds or 10 delegates as it will with 1 live.
I have a grid and there is a column which contains <a> anchor tag with some additional information in <data-..> tag and has a class name <class='myspeciallink'>. And in my unobtrusive JS script I select all the elements with that class name and apply live('click'). I need that to be live() because the grid gets generated in the runtime.
What happens inside the live('click') handler? I use that additional data and add a <div> to the page based on that data. Which in its turn used to generate jQuery UI dialog. It works great on my computer.
But! How could that work in real-world? Should I be bothered about possible performance implications? I feel that applying live() on more than a dozen elements instantaneously
would affect the performance. Especially with rather complicated handler like mine - it needs to get the data, parse the data, create a div, apply a dialog and etc.
Does that smell like a bad design? Could you suggest a different approach or my concerns are unfounded? Can I use some sort of a profiler tool to find the bottlenecks in my javascript?
UPD: Still nobody suggested any profiling tool. firebug and chrome dev tools are good, but maybe there is something even better?
live("click") is actually better up-front from a performance standpoint: Instead of binding an event handler to each matched element, you're applying a single event handler which waits for events to bubble up and then sees if the element that triggered the event matches the selector .live was called on.
Compare this to $('selector').click(...) which does loop over each element and bind a new event handler. live('click') has no additional overhead regardless of how many page elements match its selector. Depending on how many elements your selector matches, using .live can avoid a delay of up to a few seconds during the initial load of each page.
However, the event handler must check each event which bubbles up against its selector, to see if there is a match. This is going to add a small amount of overhead to every click event, but chances are very good that your users will not notice the difference.
Peter bailey also has a nice post about this: Performance difference between jQuery's .live('click', fn) and .click(fn)