Should All Jquery Events Be Bound to $(Document)

Should all jquery events be bound to $(document)?

No - you should NOT bind all delegated event handlers to the document object. That is probably the worst performing scenario you could create.

First off, event delegation does not always make your code faster. In some cases, it's is advantageous and in some cases not. You should use event delegation when you actually need event delegation and when you benefit from it. Otherwise, you should bind event handlers directly to the objects where the event happens as this will generally be more efficient.

Second off, you should NOT bind all delegated events at the document level. This is exactly why .live() was deprecated because this is very inefficient when you have lots of events bound this way. For delegated event handling it is MUCH more efficient to bind them to the closest parent that is not dynamic.

Third off, not all events work or all problems can be solved with delegation. For example, if you want to intercept key events on an input control and block invalid keys from being entered into the input control, you cannot do that with delegated event handling because by the time the event bubbles up to the delegated handler, it has already been processed by the input control and it's too late to influence that behavior.

Here are times when event delegation is required or advantageous:

  • When the objects you are capturing events on are dynamically created/removed and you still want to capture events on them without having to explicitly rebind event handlers every time you create a new one.
  • When you have lots of objects that all want the exact same event handler (where lots is at least hundreds). In this case, it may be more efficient at setup time to bind one delegated event handler rather than hundreds or more direct event handlers. Note, delegated event handling is always less efficient at run-time than direct event handlers.
  • When you're trying to capture (at a higher level in your document) events that occur on any element in the document.
  • When your design is explicitly using event bubbling and stopPropagation() to solve some problem or feature in your page.

To understand this a little more, one needs to understand how jQuery delegated event handlers work. When you call something like this:

$("#myParent").on('click', 'button.actionButton', myFn);

It installs a generic jQuery event handler on the #myParent object. When a click event bubbles up to this delegated event handler, jQuery has to go through the list of delegated event handlers attached to this object and see if the originating element for the event matches any of the selectors in the delegated event handlers.

Because selectors can be fairly involved, this means that jQuery has to parse each selector and then compare it to the characteristics of the original event target to see if it matches each selector. This is not a cheap operation. It's no big deal if there is only one of them, but if you put all your selectors on the document object and there were hundreds of selectors to compare to every single bubbled event, this can seriously start to hobble event handling performance.

For this reason, you want to set up your delegated event handlers so a delegated event handler is as close to the target object as practical. This means that fewer events will bubble through each delegated event handler, thus improving the performance. Putting all delegated events on the document object is the worst possible performance because all bubbled events have to go through all delegated event handlers and get evaluated against all possible delegated event selectors. This is exactly why .live() is deprecated because this is what .live() did and it proved to be very inefficient.


So, to achieve optimized performance:

  1. Only use delegated event handling when it actually provides a feature you need or increases performance. Don't just always use it because it's easy because when you don't actually need it. It actually performs worse at event dispatch time than direct event binding.
  2. Attach delegated event handlers to the nearest parent to the source of the event as possible. If you are using delegated event handling because you have dynamic elements that you want to capture events for, then select the closest parent that is not itself dynamic.
  3. Use easy-to-evaluate selectors for delegated event handlers. If you followed how delegated event handling works, you will understand that a delegated event handler has to be compared to lots of objects lots of times so picking as efficient a selector as possible or adding simple classes to your objects so simpler selectors can be used will increase the performance of delegated event handling.

Attaching a lot of event handlers to $(document) is bad?

No - this negatively impacts the performance of your jQuery. You should NOT bind all delegated event handlers to the document object. That is probably the worst performance scenario you could create. As mentioned in the Event Performance section here in the jQuery documentation-

Attaching many delegated event handlers to the document 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. For delegated event handling it is MUCH more efficient to bind them to the closest parent that is not dynamic.

An amazing detailed description of the problems can be found in this answer.

Hope this helps!

Why it is bad practice to register events to document in jQuery?

Event delegation basically uses 2 different process,

  1. The event bubbling, For example, when you click over an element that
    event will be bubbled up to the document to fire the relevant event.
  2. The match, after reaching the document(during event bubbling) the
    fellow who caused the event bubbling will be verified with the
    selectors attached with document. If it matches then the relevant
    event will be fired.

So you are advocating about the match by stating a generic selector. To be frank, matching 2 or 3 elements will take less time than traversing up to the document during event bubbling. At that case if you use a static closest parent instead of document, the traversing time will be reduced and that will hike the performance.

Though match takes less time, when it comes with 15+ elements for matching, that will also affect the performance even when you use closest parent instead of document.

So the summary is, we have to use event delegation sparingly with common sense by knowing the above two different process takes place under the hood.

When should you not use $(document).ready(function() for event handlers?

This should never be the case, the jQuery document ready fires when the DOM has been loaded. It doesn't wait for the complete page (included images and the like) to load. It would be extremely rare that a user would be able to react in time to try and trigger something prior your code being executed. Read this: http://api.jquery.com/ready/

Specifically, the first paragraph:

While JavaScript provides the load event for executing code when a
page is rendered, this event does not get triggered until all assets
such as images have been completely received. In most cases, the
script can be run as soon as the DOM hierarchy has been fully
constructed. The handler passed to .ready() is guaranteed to be
executed after the DOM is ready, so this is usually the best place to
attach all other event handlers and run other jQuery code.

So using $(document).ready(function() { }) or the equivalent $(function() { }) is always a good practice.

EDIT: To further ensure that the user will never have trouble, make sure your scripts are all hosted alongside your site. For instance, jQuery has the option of using a CDN. CDNs are nice, but if for whatever reason the user can get to your site but not the CDN, it could leave your page in a useless state.

Are there any drawbacks to listen events on document level in jQuery?

From the jQuery documentation available here:

Event performance

In most cases, an event such as click occurs infrequently and performance is not a significant concern. However, high frequency events such as mousemove or scroll can fire dozens of times per second, and in those cases it becomes more important to use events judiciously. Performance can be increased by reducing the amount of work done in the handler itself, caching information needed by the handler rather than recalculating it, or by rate-limiting the number of actual page updates using setTimeout.

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.

jQuery can process simple selectors of the form tag#id.class very quickly when they are used to filter delegated events. So, "#myForm", "a.external", and "button" are all fast selectors. Delegated events that use more complex selectors, particularly hierarchical ones, can be several times slower--although they are still fast enough for most applications. Hierarchical selectors can often be avoided simply by attaching the handler to a more appropriate point in the document. For example, instead of $("body").on("click", "#commentForm .addNew", addComment) use $("#commentForm").on("click", ".addNew", addComment).

jQuery: Binding events - in $(document).ready or html DOM event handler?

Also there is no load during showing the site, just if you click, am I right?

Clicking the link will only work once the show_new_messages script has loaded, so your user might see an error message if you use the onclick attribute and they click on it before the script loads. Setting up the event handler in $(documemt).ready() means that by the time the event handler is attached, all of the scripts will have loaded too, so clicking on it will work.

Should I attach my .on('click') event to the document or element

Your JSPerf here is testing the speed to attach events, not the effect that they have on cumulative page performance. This is the wrong thing to test!

Javascript events propagate up the DOM all the way to the document root. This means that if you have an on("click", ...) handler on document, then every click on every element in the document will end up running an event handler, so jQuery can test if its origin matches the delegate target, to see if it should be passed to that event handler.

Imagine that your page has 10 different delegated event handlers on document, all handling various clicks. Every time you click any element in the page, the event will bubble up to the document root, and all 10 of those handlers have to be tested to figure out which (if any) should be run.

In general, you want your delegated events to be as deep in the tree as possible while still enabling your functionality, since this limits the number of elements that may invoke this event, and you can handle the event earlier to prevent it from propagating up the DOM tree.

When using jQuery on(), why use (document) vs. the element itself?

Both of those are valid.

The former works for dynamically added elements. You use document because you're delegating events on children of the document object, so events bubble up to the document level. It's also more convenient to select the closest parent you can (and the parent must exist on the page at load).

The latter still works, and is a preferred way to simply bind events to specific elements.

I personally don't recommend delegating through the document object, but rather the closest parent that exists on page load.

Here are the docs for on().

When should I use jQuery's document.ready function?

In simple words,

$(document).ready is an event which fires up when document is
ready.

Suppose you have placed your jQuery code in head section and trying to access a dom element (an anchor, an img etc), you will not be able to access it because html is interpreted from top to bottom and your html elements are not present when your jQuery code runs.

To overcome this problem, we place every jQuery/javascript code (which uses DOM) inside $(document).ready function which gets called when all the dom elements can be accessed.

And this is the reason, when you place your jQuery code at the bottom (after all dom elements, just before </body>) , there is no need for $(document).ready

There is no need to place on method inside $(document).ready only when you use on method on document because of the same reason I explained above.

    //No need to be put inside $(document).ready
$(document).on('click','a',function () {
})

// Need to be put inside $(document).ready if placed inside <head></head>
$('.container').on('click','a',function () {
});

EDIT

From comments,

  1. $(document).ready does not wait for images or scripts. Thats the big difference between $(document).ready and $(document).load

  2. Only code that accesses the DOM should be in ready handler. If it's a plugin, it shouldn't be in the ready event.



Related Topics



Leave a reply



Submit