views:

174

answers:

7

I posted another question on a very similar topic, but turned out to be a little subjective. I am able to divided the question in two questions, one that I will explain below:

In the following Code:

<script type="text/javascript">
$(function() 
{
   $("#accordion").accordion();
   $("#datepicker").datepicker();
   $("#button").click(function() 
   {
     runEffect();
     return false;
   });
});
</script>

Question: If I have this code called in a 1,000 pages, but only 250 pages have a datepicker id. Will the browser spend extra time on the other 750 pages trying to parse for id datepicker, or Jquery has a smart way of solving this situation without affecting performance?

What happen if the code is making reference to ids or classes that does not exist on the html markup of the current page, will that impact performance?

+1  A: 

It will look for such an element, and, since there aren't any, it won't do anything.

jQuery's selector library is highly optimized for performance, so I wouldn't worry about it.

In particular, a simple #id selector is turned into a call to the browser's native getElementById, which can be assumed to be quite fast.

If you're really concerned, measure it in different browsers.

SLaks
A: 

The code will be called on every single page load and the execution would go something like this:

  • $("#accordion").accordion()
    1. Find matching elements:
      1. "#accordion" ID lookup is very fast
    2. Apply function to all matching elements:
      • if there was no #accordion element, then it's going to return virtually instantly without doing anything

You'd only want to worry about it in two cases, IMO:

  1. You have a very complex selector.
  2. You are calling a lot of functions on the element.

In case 2, which is much more common, I work around it by doing this:

$el = $('#myElement');
if ($el.length) {
    $el
        .find("div")
        .each(function () { .. })
        .parents()
    // etc...
}

I've just put together a benchmark to test how much effect this actually has. You can see the results and the code if you like:

In short:

// doing this:
var $f = $('#fakeElement');
if ($f.length) $f.find('div');

// is almost twice as fast as this:
$('#fakeElement').find('div');

// For 10000 iterations, 404ms vs 788ms in my tests
nickf
There's no particular reason not to write this as one long chain; if the first part doesn't match anything, the chain won't continue. Like: $("#myElement").find("div").each(...).parents() or even (in this example) $("#myElement div").each(...).parents().
Sixten Otto
the chain will continue... calling each function and returning an empty jQuery result set. Depending on how many functions you have chained there, the overhead (even from an empty set) could add up significantly.
nickf
@Sixten: see the test results I've just edited into this answer... even with only one simple `.find` on an empty set, it is *much* slower.
nickf
+1  A: 

Yes, technically jquery will spend some amount of time looking for an element with an id of 'datepicker'.

However, since you're selecting by and ID, and you're only doing it once per page, the time it takes is probably so small that you can't even reliably measure it.

Now, you might want to worry about this if this code were somehow buried inside a loop and was going to get executed with insane frequency. But that doesn't look the case.

This is small stuff, don't sweat it. I'm sure if you look hard enough, you can find a dozen optimizations that will pay off much better than worrying about this.

timdev
A: 

Since jQuery is stateless it will have to look this up. You could limit the impact by setting the element in a variable and then whenever you need this, you look at what you saved in the javascript code, and just use that.

Optimizations like this can help with any performance concerns, though, as SLaks mentioned, this call is very fast, but, you can time it on different browsers, and see if you want to speed it up.

James Black
+4  A: 

For those saying "don't worry about it" I couldn't disagree more.

I built a site like this once where the external JS file had:

$(function() {
  // do lots and lots of stuff
});

with no Javascript internally on the HTML (PHP) page. It was a performance disaster and that was with relatively efficient selector choice, meaning never:

$(".someClass").doStuff();

Instead:

$("div.someClass").doStuff();

and so on. It took about a second to execute all the Javascript even though 95% of it was doing nothing. My advice? If you want a highly responsive Web site don't do it this way.

Instead put functions like this in your external JS:

function activate_accordion() {
  $("#accordion").accordion();
}

This is of course a simple example. But the point is this: no Javascript should be automatically executed in your external Javascript file unless the vast majority of pages use it. Your external Javascript file should just be a collection of functionality that is called where necessary on individual pages.

and then on each page inside the HTML put:

<script type="text/javascript">
$(function() {
  activate_accordion();
}
</script>

so you only execute the Javascript you are actually using. Yes this is slightly more work because you have to be aware of what each page is doing/using but doing it globally can quickly get out of hand.

I reduce the Javascript execution times to 50-100ms (from 1-2 seconds) this way.

cletus
Let me see if I get what you are saying. You define your functions on the global include called activate_{functionname} and then you add on the markup that uses that function the actual activate_{functionname} call. So at the end you have a contract with all your activate_{functionname} and you can add all the functions that are needed in each page on the markup. is this accurate?
Geo
That's it exactly. There are however many variations upon this theme. For example, you could have a function called use() or import() and give it a list of constants for functionality to use on the page. YUI uses this approach but it handles dependencies automatically as well.
cletus
Thanks for the information. I could not understand the use() import() analogy, but thanks in general.
Geo
A: 

If you have a large chunk of code that is dependent on the existence of an element, you can always conditionally execute it:

if( $('#accordion').length > 0 ){
     // 20 lines of #accordion-dependent code here
}
cpharmston
A: 

Why not mix in a native call?

Each of the following ran for 10,000 iterations.

$('div#datepicker');
// 179ms

$('#datepicker').find('div');
// 65ms

var $dp = $('#datepicker'); if ($dp.length) $dp.find('div');
// 32ms

if (document.getElementById('datepicker')) $('#datepicker').find('div');
// 1ms
theGman