简体   繁体   中英

Optimize live elements' selectors in jQuery

I read a lot about optimization in jQuery in some links below:

  1. jQuery Website , Performance
  2. jQuery Best Practices - Greg Franko
  3. jQuery Coding Standards and Best Practices
  4. 14 Helpful jQuery Tricks, Notes, and Best Practices

and more ... But none of them mentioned for .on() caching selectors. I don't know if there is any way to use cached elements in these kind of selectors.

for example I have a lot of these selectors in my script.js file.

$(document).on('click', '.menu li.remove', function(e){ ... });
$(document).on('click', '.menu li.edit', function(e){ ... });
$(document).on('click', '.menu li.action', function(e){ ... });
$(document).on('click', '.menu li.anotherAction', function(e){ ... });

and much more. .menu is a menu and can be anywhere in document, so I can't use specific id container to select it. like this:

$('#sidebar').on('click', '.menu li.action', function(e){ ... });

is there any way to optimize these selectors. Checking for existence maybe, caching .menu if it is possible.

When you need to eek out every last bit of performance, you probably need to ditch abstractions.

If you do your own delegation, you'll certainly see a performance improvement.

Because in the example you gave, all the delegation is identical except for the class name, I'd bind a single handler, put the code in separate functions, and then examine the e.target and its ancestors manually looking for the .menu li . If that's found, then check the class of the li , and invoke the correct handler.

var handlers = {
    remove: function() {/*your code*/},
    edit: function() {/*your code*/},
    action: function() {/*your code*/},
    anotherAction: function() {/*your code*/}
};

var targets = Object.keys(handlers);

document.onclick = function(e) {
    e = e || window.event;
    var li;
    var node = e.target || e.srcElement;
    var targetClass;

    do {
        if (!li) {
            if (node.nodeName === "LI") {
                li = node;
            }
        } else if (node.className.indexOf("menu") > -1) {
            targetClass = li.className
            break;
        }
    } while(node = node.parentNode);

    if (!targetClass)
        return;

    for (var i = 0; i < targets.length; i++) {
        if (targetClass.indexOf(targets[i]) > -1) {
            handlers[targets[i]].call(li, e);
        }
    }
}

In the code above, as we traverse up from the e.target , we first check to see if we're on an li . If so, grab it and continue one.

As we continue, we no longer need to check for li elements, but we now need to check for an element with the menu class. If we find one, we grab the class name of the li we previously found and then halt the loop.

We now know we have our menu li.someClass element. So then we can use the class that we found on the li to look up the proper function to invoke from our list of functions we made above.


You should note that my .indexOf() class testing is ad hoc, and could result in false positives. You should improve it. Also, the code needs more tweaking since we're caching the li without knowing if it actually has a class that we're interested in. That should be fixed as well.

I'll leave it to you to add the necessary tweaks if you desire. :-)

I personally think you are worrying about speed where speed is not an issue.

If the menus are not loaded dynamically, there is nothing stopping you from combining delegated event handlers with normal jQuery selectors to target more of the closer elements (eg your .menu class):

eg

$('.menu').on('click', 'li.remove', function(e){ ... })
 .on('click', 'li.edit', function(e){ ... })
 .on('click', 'li.action', function(e){ ... })
 .on('click', 'li.anotherAction', function(e){ ... });

This will create a handler on each menu (so closer to the elements).

If your menus are dynamically loaded, then your existing code is perfectly fine , as my understanding is that delegated event handlers only apply the selector argument to the elements in the bubble chain. If that is the case, delegated events will be pretty darn fast anyway. Certainly faster than you can click your mouse! I have never had speed issue with delegated event handlers and I probably overuse them in my plugins (I always assume dynamic content in those).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM