6

Initial instincts tell me that adding a listener, either using bind or a straightforward event method to a jQuery set of elements, such as..

$('.className').click(funcName);

Is much more appropriate than using a $.each method to add a listener one by one to the same set, as...

$('.className').each(function(){ $(this).click(funcName); });

But when it comes to plugin development, and you are dealing with the possibility of users calling an instance of your plugin multiple times throughout the lifetime of a page, on page load and through ajax long after page load, is it wrong to apply handlers to each element itself, rather than trying to abstract the handlers to their global class set?

My main question I'm dealing with is "What is the best way to deal with multiple instances of a plugin being called when it comes to event handling? As to reduce the workload?" I know we can bind and unbind, but is there a better way?

EDIT

partial code from plugin construct

init : function(){

  this.each(function(opts){

  // adding event handlers here removes
  // the need to worry about multiple instances
  // and duplicate handles over the lifetime of the page

  });

  // adding 'global' handlers here may/may not be more
  // efficient, but adds an issue of multiple instances

  return this;

}
anson
  • 4,156
  • 2
  • 22
  • 30

4 Answers4

4

If you call click once, jQuery will loop through the whole collection and bind the events individually. However, it will do it more efficiently than your alternative, because it does not build a new jQuery object for each element in the set, which will be very slow.

Here is the code from the jQuery source (it's the on method):

return this.each( function() {
    jQuery.event.add( this, types, fn, data, selector );
});

(event.js, line 936-8)

jQuery.event.add, which is the method that does the heavy lifting, does not need a jQuery object; the plain DOM object is what it needs. This loop (which effectively does the same thing as yours) is much superior in terms of efficiency, because the big bottleneck in your code is $(this) being called every time.

Note that the most efficient technique would be using event delegation with the same on method. This might look like this:

$(document.body).on('click', '.className', funcName);

This means "for every click inside document.body, check to see if it originated on an element matching the selector .className, and if so run funcName". You could replace document.body with any other element that contains all the potential .className elements.`

thirtydot
  • 224,678
  • 48
  • 389
  • 349
lonesomeday
  • 233,373
  • 50
  • 316
  • 318
  • Can you provide an example of what that would look like? – Fresheyeball May 09 '12 at 17:27
  • Thanks for this answer, its definitely good information on the way things are ran internally. However, I am more concerned in the plugin scope of things. The general 'init' method for plugin development will use $.each to loop the set anyways, so I already have to do a loop of the element set. The question is whether to bind events in the loop, or globally afterwards. I'll edit my question to explain... – anson May 09 '12 at 17:40
  • *"...build a new jQuery object for each element in the set, which will be very slow."* [This isn't true](http://stackoverflow.com/q/10433014/201952) -- doing `$(this)` in an `each` is so small of a performance hit, it's not worth worrying about. – josh3736 May 09 '12 at 18:01
  • @josh3736 it depends on the size of the application. Over use of jQuery objects is a big problem in current javascript development. It may be a small performance hit alone, but it adds up, and is worth avoiding. – Fresheyeball May 09 '12 at 18:05
  • @Fresheyeball, in the question I linked to, you'll see that even over unrealistically large numbers of calls (thousands per second) to `$(this)`, the performance hit is only 7%. (If you're attaching thousands of event handlers, there's a much larger problem.) The point here is this is probably a premature optimization; don't make development and maintenance a nightmare by adding complexity for tiny runtime gains. – josh3736 May 09 '12 at 18:14
  • 7% is big enough to worry about in my book, because it might be thousands. But I agree with you about maintainability. I personally use the `.each` pattern where it makes sense to me and if I know there is a reasonable number of calls, its not a big deal. However this user asked the question as to which is more efficient, so I stand by my answer. Additionally, if not using `.each` is an option, its actually LESS complex. – Fresheyeball May 09 '12 at 18:21
1

Your question is about "efficiency," which I assumes means "speed on the client". Probably any reasonable approach will have minimal impact on perceived performance, so I recommend you pick the coding pattern that is easiest to maintain.

Yusuf X
  • 14,513
  • 5
  • 35
  • 47
1
$('.className').click(funcName);

less load as it uses a single jquery object

$('.className').each(function(){ $(this).click(funcName); });

more load as it uses the initial instance, and also generates a new instance for each 'eached' element via $(this). If $('.className') contains 50 elements, you now have 51 jQuery objects, versus a single object.

As far as pluggin development, you can use javascript objects and use new for each instance of the plugin. Or you can define a parent object class, and use .each on that to set up instances. I hope this helps, it hard to make a recommendation without knowing what your are cooking.

Fresheyeball
  • 29,567
  • 20
  • 102
  • 164
0

The only real way to know is to profile it. However, I'd wager that this is an exercise in premature optimization.

Calling $(this) in a loop has a negligible runtime performance hit.

If it's easier and cleaner to attach your handlers in an each loop, do it.

Community
  • 1
  • 1
josh3736
  • 139,160
  • 33
  • 216
  • 263