views:

126

answers:

5

This gets and stores the background color of a specific link:

var origColor = $("ul.relatedAlbums li a").css("background-color");

But there are a lot of those links, and I get the feeling that this is ineffecient. I imagine there's a way to tell the selector query to stop after the first match, and thus save on processing time. Here's how I imagine doing that:

var origColor = $("ul.relatedAlbums li a:first").css("background-color");

Is this the right / efficient way to do it? People say that using css pseudo classes is slow - but I'm not sure if that applies. This just has the same syntax, is that right?

+5  A: 

You don't need the :first because the css-method only looks at the attribute of the first element in the set of matched elements.

http://api.jquery.com/css/
css( propertyName )

Get the value of a style property for the first element in the set of matched elements.

RamboNo5
in fact, it has been shown that :first can actually be slower than not using it at all: http://api.jquery.com/first-selector/
Scott Evernden
@Scott Evernden - Not surprising at all, considering that the get version of the `.css()` function uses `elem[0]` where the `:first` selector uses a `filter` with a callback function of `function(elem, i) { return i===0; }` which will get applied to every element.
gnarf
+1  A: 

jQuery's selector engine handles the :first selector by first searching for ul.relatedAlbums li a then applying a filter against all the matching elements. Although this filter is pretty short:

first: function(elem, i){
  return i === 0;
}

It still generates a function call for EVERY element in the selector.

The .css(prop) method will return jQuery.curCSS(elems[0], prop). Therefore the :first selector is purely a waste performance wise.

gnarf
A: 

what RamboNo5 said, but if you want to edit the background color only for the first element you can use

var origColor = $("ul.relatedAlbums li a:first").css("background-color", "red");

as you said, but i think you could also use

var origiColor = $("ul.relatedAlbums li").first().css("background-color", "red");

I haven't tried it, but I think it should work and I do believe that it is faster, since you don't require selector parsing.

take a look at: - api.jquery.com/first-selector/ - http://api.jquery.com/first/ for further information

A: 

I don't think the :first selector will buy you much.

One of the best ways to improve performance with a selector is to utilize the optional context parameter with an id selector.

Something like this...

var origColor = $("ul.relatedAlbums li a", "#surroundingDiv").css("background-color");

That 2nd context selector actually tells the jQuery engine to first search the DOM for #surroundingDiv. And then those results are narrowed further with the first selector.

Since id selectors are by far the fastest of all selectors, this technique can sometimes double performance depending on the relative size of the context compared to the rest of the DOM.

Steve Wortham
+7  A: 

Weird as it may sound, I am getting "a:first" consistently faster on Safari, and Firefox, and slower on Chrome and Opera on these tests. However, these results are for almost 12,000 links on the page, so a millisecond here or there is not worth pulling hairs over.

Safari

alt text

Firefox

alt text

Chrome

alt text

Opera

alt text


To really optimize this, you should never select all links. Assign a unique ID to the first link, and access only that. Here is a new test with searching a single element, and it blows the other techniques out of proportion. Needless to say that this was obviously going to be really fast, but this is just a comparison of actually how much faster.

OK, I can't resist adding jQuery style performance numbers from its 1.0 days :)

Safari (112,000% faster)

alt text

Firefox (30,000% faster)

alt text

Chrome (24,000% faster)

alt text

Opera (38,000% faster)

alt text

Setup:

  • OS: OS X 10.5.8
  • Opera: 10.10, build 6795
  • Chrome: 5.0.375.70
  • Safari: 4.0.5 (5531.22.7)
  • Firefox: 3.6.4
Anurag
+1 What a great answer.
James Westgate