Large DOM Tree Slowing Down jQuery Click Events

2020-06-22 08:49发布

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?

1条回答
混吃等死
2楼-- · 2020-06-22 09:11

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.

查看更多
登录 后发表回答