Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Large DOM Tree Slowing Down jQuery Click Events

Problem Solved!

This problem (specific to my configuration) has been solved by Dhoelzgen and Matthew Blancarte as per the accepted answer. The jist of the problem was that I was binding 'click' events to all the .inventory_item elements when I should have been using jQuery's on method to delegate the event handling, like so:

<head>
    <script>
        $(document).ready(function(){

            $('#inventory_index').on('click', '.inventory_item', function(){
                alert('Click event fired!');
            });

        });
    </script>
</head>

Using this technique I've greatly, greatly increased the responsiveness of my app.

Continue reading for all the details ...

Overview

I'm working on an inventory app that runs in a 'single page' (e.g. www.myapp.com/app.php) and uses jQuery to execute XHR's to load the various content in and out of DIV's.

I'm using jQuery 1.9.1 and jQuery UI 1.8 (because I have to for legacy reasons).

The Problem: Slow Click Events

The problem I'm having is that the click events get slower and slower as the DOM tree grows larger. The delay is currently about 2 seconds when ~1000 items are returned from a search.

Here's the example jQuery:

<head>
    <script>
        $(document).ready(function(){
            var inventory_item = $('#inventory_index.inventory_item');

            inventory_item.on('click', function(){
                alert('Click event fired!');
            });
        });
    </script>
</head>

And the HTML:

<div id="inventory_index">
    <div class="inventory_item">Inventory Item 0 <img src="inventory_item_0.jpg"></div>
    <!-- 999 Iterations -->
    <div class="inventory_item">Inventory Item 1000 <img src="inventory_item_1000.jpg"></div>
</div>

At first I assumed it was because of the images that reside within each of the .inventory_item's, but after implementing lazy-loading I discovered that the issue had more to do with the number of elements in the DOM than it did with the images themselves.

Attempted Solution

As you can see in the example code above, I've already tried to implement the best solutions I could find over the past couple of days. Namely, wrapping the collection of .inventory_item's in an ID-able #inventory_index element to give jQuery a hint as to where it should be looking.

And, additionally, creating a javascript object to try and shave even more time off the DOM search (although, to be honest, I'm not sure exactly how that works, or if it's helping at all).

Has anyone else run into this problem and have any solutions or advice they could share?

Current Best Idea

As of right now, the only way I've imagined this could be solved is to simply reduce the number of elements in the DOM tree by loading less results into the #inventory_index. This is an option, but I'd really like to retain the ability to load up hundreds, if not thousands of .inventory_item's into the index.

BONUS

Oddly enough, the mouseenter and mouseleave events fire instantaneously. You can see a similar problem here:

jQuery delegate performance on the click event on large lists - slows down if you dynamically add more elements?

like image 271
AJB Avatar asked Apr 26 '13 20:04

AJB


People also ask

What causes excessive DOM size?

Excessive DOM size happens when there are too many DOM nodes (or HTML tags) on your page or when they are nested too deep. This causes the user's browser to consume additional power to process your web page, leading to slow page loading and low page speed scores.

What is large DOM?

A large DOM tree often includes many nodes that aren't visible when the user first loads the page, which unnecessarily increases data costs for your users and slows down load time. Runtime performance. As users and scripts interact with your page, the browser must constantly recompute the position and styling of nodes.

What does DOM size mean?

All the objects that constitute the HTML structure of the page, i.e. all the tags included in it (HTML, BODY, DIV, H1, H2, etc), are called nodes and the sum of them is translated as the DOM size.

How an event handler behaves like?

In the context of the event loop, as discussed in Chapter 11, browser event handlers behave like other asynchronous notifications. They are scheduled when the event occurs but must wait for other scripts that are running to finish before they get a chance to run.


1 Answers

What about using jQuery's on method to attach an event handler like this:

$('#inventory_index').on('click', '.inventory_item', ...)

This way, you would only add a single event handler, instead of one for each inventory item. Haven't tested it, just stumbled about the fact that you add a lot of event listeners.

Some explanation:

If you use $('#inventory_index .inventory_item') as a selector, you end up binding a single event handler to each inventory item which is a problem especially if you have many of them. On the other hand the #inventory_index selector above just adds a single event handler to the element used as a wrapper, which is responsible for handling all the clicks on the elements filtered by the second selector, which is the second argument .inventory_item in the on method call.

like image 158
dhoelzgen Avatar answered Oct 24 '22 15:10

dhoelzgen