7uchvg
Last Updated: July 05, 2016
·
15.06K
· argyleink
4146f0a7de7dbfd047abe6e7fda1b407

DO NOT $('#foo a'); DO $('#foo').find('a');

Don't
$('#foo a');

Do
$('#foo').find('a');

Imagine you are asked to find every student in a highschool, then told to find the students inside classroom #123. Doesn't feel efficient does it?

Imagine now you are asked to find room #123, then told to find every student.

This is exactly how it is for jQuery and the DOM. Selecting by ID is super quick, and if you use an id to find an element first, then the next part of the search only has to happen on it's children, instead of the whole page!

This will increase your app 20 fold. Do it.

Say Thanks
Respond

35 Responses
Add your response

71
A04db665526e5cadab5dd79dfa665659

@nvartolomei So, if I understood: $('div a') <- OK $('div').find('a') <- BAD $('#foo a') <- BAD $('#foo').find('a') <- OK

over 1 year ago ·
877
13027845faeb65d26acd203f755ceb21

I was under the impression, somehow, that whilst the selector engine does work right to left that it does optimise easy stuff like ID selection?

That said, for less generic cases, minimising the search space is definitely a good idea. You can also compact it a little by doing jQuery('a', '#foo')

over 1 year ago ·
889
44e4c29e4522a91f6c6ae8448f558a74

Maybe you could link to an actual http://jsperf.com/ link.

And maybe you'll see that the performance gain is worth only when you are doing billions of jQuery selects in a for loop.

So, if you're not doing it in a for loop then your wasting your time trying optimizing something that only happens once.

over 1 year ago ·
897
Avat

@vvo I think this approach could go not only in the optimization sense, but more in a coding ethics and good practices mode.

That said, I do agree, the narrowing the selections in the "search selector" is a great approach.

over 1 year ago ·
1010
Alex

Looks like it doesn't matter, at least for new browsers.

http://jsperf.com/wtfasdasdasd/2

over 1 year ago ·
1025
4146f0a7de7dbfd047abe6e7fda1b407

burntime, those results are crazy. looks like i can write a selector any way i want to now. is it jquery fixing and optimizing my bad selector or is the browser?

over 1 year ago ·
1252
A367f00d21bc986d5f74f6b56dabddb6

@burntime: I think your test should prepare a more realistic, i.e. much bigger DOM. If the original protip was right and $('#foo a') had a complexity of O(n) and the faster one O(1) than the difference would only show by having a big enough n.

over 1 year ago ·
1284
3d58bab92b2165d78b9d325085a75702

I don't think this is true. jQuery uses Sizzle, and Sizzle is smart enough to lookup nested elements. Seeing how the most left is #foo, it will first grab foo, and then look for 'a'. This might be different for other browsers, but I'm pretty sure Sizzle is smart enough.

over 1 year ago ·
1296
A0732ec2caf7c3335e9b4a834d8d075a

AFAIK $("a", "#foo") == $("#foo").find("a")
"$(subject, context):: Find 'subject' in 'context'"

over 1 year ago ·
1299
4146f0a7de7dbfd047abe6e7fda1b407

this tip in vanilla js = document.getElementById('foo').querySelector('a'). just throwing that in there so the practice can extend into non-jquery js apps.

over 1 year ago ·
1381
A510a332dd609f34f1adb36d3235286b

It is important to know that jQuery Selectors are handled left to right! The whole "protip" suffers from the misunderstanding that jQuery would work like CSS (right to left).

That's why the analogy with the students in room is wrong.

Doing $('a #foo'); would be searching all students and then find the students from room 123. And it would be very inefficient in the DOM.

Doing $('#foo a'); is similar to $('#foo').find('a'); and only has the performance impact od deconstructing the String "#foo a" into "#foo" and "a" (and function calls. The DOM traversion should be nearly the same.

// Update 2012-12-03:
As @mlb has said, in general, Sizzle selectors are handled right-to-left. Exception: when there is an ID as the first element/operand – which is the subject of this discussion – then jQuery/Jizzle optimizes it by first selecting the ID element and then searching inside it. (At least that is what I have found.)

over 1 year ago ·
1700
Deleted photo instagram

Why should I have to compensate for a bad implementation? If $('#foo').find('a') is faster than it should be what $('#foo a') translates to inside of jquery. I shouldn't have to worry about it.

over 1 year ago ·
1705
Da547139569ae1a1aa2303587cfbdb42

Don't do that "do", do that as @cyrusboadway did.

over 1 year ago ·
1732
E31d9d39e9fb0ec4cc5573a5e5b01ce7

But what if I have a more complex query: like $("#foo div.something a"), then do I use $("#foo").find("div.something").find("a")? Kind of long ...

over 1 year ago ·
1735
6129328da602246ffcbd20dae42e70c3

I created a test at jsperf a whole back that covered this in a little more detail: http://jsperf.com/jquery-context-or-no-context

over 1 year ago ·
1819
144314100b686db946ff68c7ae1065d1

jQuery find() convention has bad performance

For DOM queries use Cascading $('#foo a') or parent > child $('#foo > a').

// bad
$('#foo', 'a').hide();

// bad
$('#foo').find('a').hide();

// good
$('#foo a').hide();

// good
$('#foo > a').hide();
over 1 year ago ·
2078
81829def637962204635704c091036ea

@thomaspuppe Sizzle selectors are handled right to left. Your whole comment suffers from this wrong belief.

over 1 year ago ·
2129
A7c1c674da67d39722b33610dad1a761

@thomaspuppe This "protip" showed up in my e-mail box and I read it with horror. Thank God your correction is the top comment.

over 1 year ago ·
2163
A510a332dd609f34f1adb36d3235286b

@mlb You are absolutely right! Sizzle selectors are handled right-to-left.

Is this something that has changed recently? I always believed jQuery works left-to-right, and noone ever disagreed. Maybe it is because I am used to put IDs as the first operand, and have this in examples and tests as well.?

EXCEPTION: when there is an ID as the first element/operand – which is the subject of this discussion – then jQuery/Jizzle optimizes it by first selecting the ID element and then searching inside it. (At least that is what I have found.) This behaviour is like working left-to-right .

Sizzle is highly optimized and I guess they have different behaviour for different selectors and also take browser features into account.

In general, I can only repeat the advice some people already gave: Testing a certain solution onj jsperf (or similar) is always a good idea. E.g.: http://jsperf.com/specific-left-or-right

over 1 year ago ·
2169
81829def637962204635704c091036ea

@thomaspuppe By the way I usually recommend to jQuery users to create a helper like :

function $$(id){return $(document.getElementById(id))}

Even if '#id' selectors are optimized, they remain really slow compared to the helper,

over 1 year ago ·
2252
6f400a5624bdf137bf1aed7e128f0e7f

Just wanted to note that this is only correct when searching by ID.

Searching by tag name yields different results in modern browsers where $('div').find('p')</code> is slower than $('div p')</code> because the latter uses querySelector().

http://jsperf.com/find-vs-sizzle-jf

over 1 year ago ·
2310
Add92525ab635b5119671269d24c1449
over 1 year ago ·
2600
Ca85e937926a84231055f0adbaeac6c3

I personally would very much prefer to use plain old JavaScript for selecting child elements 'p' of an element #id. I would also recommend doing it this way as well, especially after having added a couple more tests to the jsperf and seeing just how extremely much faster it is to do what I told my friend I'd do instead by default. http://jsperf.com/wtfasdasdasd/5

var p = document.getElementById('id').getElementsByTagName('p');
$(p);

Plus, you can set it to a variable which can be passed to jQuery for selecting it and using it's context.

over 1 year ago ·
3556
D42a7264714dee5006b9c99d2567a320

Obvious but I loved the metaphor with classroom! :)

over 1 year ago ·
3614
3575018741e0d4a2214747708456797f

thanks for explaining what is happening here. I just used find() for the first time today and didn't realized how much more efficient it is.

over 1 year ago ·
5206
D940dd93751cea6229c4b9b2098b7f39

Just wrote what I think is a more comprehensive test scenario:

Note that the performance varies between the nested and flat DOMs.

over 1 year ago ·
5870
B22db59bb266a4d7624db92bfad9894b

@burntime oh, I did not know that app. Thank you very much!

over 1 year ago ·
6575
2f18a281f9f8a30e4c491037d938be5c

The difference in actual runtime performance here is so tiny, I doubt if it matters in any real-world use case (who on earth matches millions of selectors, not to mention in a loop over time?).

Just use what's more readable and makes sense in your context. If you nailed the big stuff, tweaked the medium issues and ran out of micro-optimizations, come back to this tip.

over 1 year ago ·
6964
Pppp

Exactly. I am wondering what kind of understanding author has. @argyleink.: Get some reading before you make so called PRO-TIP.

over 1 year ago ·
8102
073c064ab48784d97f233d8c07cfa280

So I guess we can not call it PROTIP

over 1 year ago ·
8331
E508619a35122f55616b9332f00b9e47

I've noticed that about an alarmingly large number of "pro-tips" on this site. Most of the ones I read in a sitting are either incomplete or flat out wrong. Too bad this site is more about vanity and less about actual knowledge (i.e. StackOverflow) or else there might be a better system for squashing anti-knowledge.

over 1 year ago ·
8757
44e6a6fcf36cf8f23ebb6b41b834e417

There's tons of optimizations in JQuery and sizzle and then since they use DOM too, there's another set of optimizations are done. What I'm saying is that no matter how much you know about JQuery, Sizzle(, or even a certain browser internals and how it deals) it wouldn't be easy to just predict what operations will faster. There's too many optimizations that may or may not happen. I suggest you all read this two:

http://mrale.ph/blog/2013/04/29/performance-tuning-as-weather-forecast.html
http://mrale.ph/blog/2012/12/15/microbenchmarks-fairy-tale.html

If you want what is faster, write a real world test case for both cases. At times it may not be even noticeable. And again don't just try to predict stuff like this. If were you I would go with $('#foo a'); because it's easier to read. Later IF I FEEL MY APP IS SLOW , I'll profile it. If $('#foo a'); was the bottleneck, I just replace it with something efficient, but this I make sure I'll measure it correctly.

over 1 year ago ·
10447
C4df3fcb6e26d2cd50a8bc99a6346cce

I like the analogy, however it's up to jQuery to interpret the query. It could be that both queries are the same, ie, jQuery could split the query "#foo a" to $("#foo").find("a") to optimize performance. However good or bad can't be determined just by basing on the analogy, it must be benchmarked and looked at the source.

over 1 year ago ·
12535
Ceef79191efd23932c20696353d44bd2

similarly, do: $(document).on('click','.fancybutton', function(ev) { /* ... */ });

over 1 year ago ·
13991
8989eee4889947f5699521ebaab08a0e

It's different things

over 1 year ago ·