102

As far is I know, there are a number of ways of selecting child elements in jQuery.

//Store parent in a variable  
var $parent = $("#parent");

Method 1 (by using a scope)

$(".child", $parent).show();

Method 2 (the find() method)

$parent.find(".child").show();

Method 3 (For immediate children only)

$parent.children(".child").show();

Method 4 (via CSS selector) - suggested by @spinon

$("#parent > .child").show();

Method 5 (identical to Method 2) - according to @Kai

$("#parent .child").show();

I'm not familiar with profiling to be able to investigate this on my own, so I would love to see what you have to say.

P.S. I understand this is a possible duplicate of this question but it doesn't cover all methods.

Community
  • 1
  • 1
Marko
  • 71,361
  • 28
  • 124
  • 158
  • Also, @spinon - is that only for immediate children? The CSS spec says "Matches any F element that is a child of an element E." – Marko Jul 05 '10 at 07:39
  • 7
    You don't really have to worry which of that is faster(unless you're doing a really big dom manipulation)... jQuery was built to be awesome fast... – Reigel Gallarde Jul 05 '10 at 07:41
  • I have a 2MB HTML file, don't ask how or why :) – Marko Jul 05 '10 at 07:43
  • 1
    Yes. First level descendants only. – spinon Jul 05 '10 at 07:43
  • There is one more way. $("#parent .child").show(); which is identical to the way #2 . :) – Kai Jul 05 '10 at 07:54
  • I've added that in as well for future reference – Marko Jul 05 '10 at 07:58
  • `$("#parent .child").` is by far the slowest. Semantically, it may be identical, but parsing the selector is very slow. http://jsfiddle.net/QLV9y/1/ – Aaron Butacov Jul 05 '10 at 08:32
  • Agreed - thanks @Aaron! It would be great if someone could summarize these results for the sake of easy reading for other viewers, there's about 20 comments on this page... I'd hate to write my own answer and accept it, but I think a tidier solution is needed. – Marko Jul 05 '10 at 08:39
  • Scope is always faster for me. Though it's by a fraction so it's just for the sake of the argument. :) Here's my results http://tinyurl.com/279uav3 – Marko Jul 05 '10 at 08:45
  • @Marko, I've updated with a complete summary. – Aaron Butacov Jul 05 '10 at 08:51

3 Answers3

95

Method 1 and method 2 are identical with the only difference is that method 1 needs to parse the scope passed and translate it to a call to $parent.find(".child").show();.

Method 4 and Method 5 both need to parse the selector and then just call: $('#parent').children().filter('.child') and $('#parent').filter('.child') respectively.

So method 3 will always be the fastest because it needs to do the least amount of work and uses the most direct method to get first-level children.

Based on Anurag's revised speed tests here: http://jsfiddle.net/QLV9y/1/

Speed test: (More is Better)

On Chrome, Method 3 is the best then method 1/2 and then 4/5

enter image description here

On Firefox, Method 3 is still best then method 1/2 and then 4/5

enter image description here

On Opera, Method 3 is still best then method 4/5 and then 1/2

enter image description here

On IE 8, while slower overall than other browsers, it still follows the Method 3, 1,2,4,5 ordering.

enter image description here

Overall, method 3 is the overal best method to use as it is called directly and it doesn't need to traverse more than one level of child elements unlike method 1/2 and it doesn't need to be parsed like method 4/5

Though, keep in mind that in some of these we are comparing apples to oranges as Method 5 looks at all children instead of first-level ones.

Zoe
  • 27,060
  • 21
  • 118
  • 148
Aaron Butacov
  • 32,415
  • 8
  • 47
  • 61
  • By identical you mean that they both use the same logic to search? – Marko Jul 05 '10 at 07:35
  • 4
    Don't you mean that method 1 and 2 are identical? – Guffa Jul 05 '10 at 07:36
  • Thanks @Aaron - tI'd like to see what the others think, I will accept your answer if everyone agrees. Cheers :) – Marko Jul 05 '10 at 07:41
  • @J-P, I mean it needs to take the extra bit of time to recognize that a scope is being passed to translate it into the `$parent.find(".child");` command. – Aaron Butacov Jul 05 '10 at 07:51
  • Well those results contradict Method 4, since it takes the longest to complete. Does .filter(".child") really take that long to complete? If Method 4 calls children() then filter() we shouldn't see that much of a delay? – Marko Jul 05 '10 at 08:17
  • Also @Aaron - Are you able to add @Anurags link to your answer? It's an excellent test :) Furthermore, Method 1 and 2 don't appear to be identical, the scoped test seems to be running slightly faster, as opposed to the other way around. – Marko Jul 05 '10 at 08:22
  • @marko, for me, scoped runs about 300 operations/second slower. For method 4, the loss is in parsing the string into the functions not calling the functions. @anurag, thanks that works perfectly. – Aaron Butacov Jul 05 '10 at 08:28
  • That's an interesting result then, what browser are you using? On average, scoped runs about 200 op/s faster for me. In Firefox 3.6.4 – Marko Jul 05 '10 at 08:35
  • I'm using firefox 3.6 see http://tinyurl.com/2e89tp5 for my stats, on chrome I got very different numbers (see image in post above). But if you run it multiple times in a row, you'll find that the numbers change. Opera was really surprising, Method 1/2 are the slowest on it: http://tinyurl.com/2a9r9r8 – Aaron Butacov Jul 05 '10 at 08:39
  • 2
    @Aaron @Marko - The tests might be a little skewed as we're always using the root node as context, and the document is pretty big. Despite that, I'm seeing 1 and 2 line up within 20 ops/sec to each other on most runs. Compared to 1 and 2, 4 is about 100-200 ops slower, and 5 is about 400 ops slower which is understandable because it goes through all descendants and not just children. Chart - http://tinyurl.com/25p4dhq – Anurag Jul 05 '10 at 08:47
  • That's excellent, thanks to everyone for their input. @Aaron, if you could just add a note that Method 3 only finds immediate descendants, we don't want people to confuse it with the other 4. Also, here's an IE8 reference, had to download a .php file to extract the URL :) http://tinyurl.com/2a8ag59 – Marko Jul 05 '10 at 08:55
  • @Aaron Harun: Just a hint: if you want to create JSLitmus-based JavaScript performance test cases more easily, just use [jsPerf](http://jsperf.com/). – Mathias Bynens Aug 01 '10 at 15:57
  • Interesting. http://jsperf.com/jquery-children-vs-find seems to suggest that .find is a lot faster than .children. – comecme Jan 16 '15 at 17:59
  • That test is not selecting classes, it's testing something else entirely. `.find()` is faster with classes. http://jsperf.com/jquery-children-vs-find/100 – Aaron Butacov Mar 28 '15 at 13:24
13

Method 1

Can't be shorter and faster using jQuery. This call directly gets down to $(context).find(selector) (method 2, due to optimazation) which in turn, calls getElementById.

Method 2

Is doing the same, but without some unnecessary internal function calls.

Method 3

using children() is faster than using find(), but of course, children() will only find direct childrens of the root element whereas find() will search recursivly top-down to all child elemens(including sub child elements)

Method 4

Using selectors like this, has to be slower. Since sizzle (which is the selector engine from jQuery) works right to left, it will match ALL classes .child first before it looks if they are a direct child from id 'parent'.

Method 5

As you stated correctly, this call will also create a $(context).find(selector) call, due to some optimazation within the jQuery function, otherwise it could also go through the (slower) sizzle engine.

alex
  • 479,566
  • 201
  • 878
  • 984
jAndy
  • 231,737
  • 57
  • 305
  • 359
  • 2
    You're not talking about the var $parent = $("#parent") are you? I can't see how Method 1 could use getElementById when the element has a class? – Marko Jul 05 '10 at 07:44
  • 1
    I wanted to agree but, in method 1, docs says, `Internally, selector context is implemented with the .find() method` -please update, I know you got confused on the labels of the OP :) – Reigel Gallarde Jul 05 '10 at 07:49
  • @Reigel: true fixed that. @Marko: parsing `#parent` represents an id, if it is a class, it will not use `getElementById` obviously. – jAndy Jul 05 '10 at 07:55
10

As it is an old post, and things change with the time. I did some tests on the last browser versions so far, and I`m posting it here to avoid misunderstandings.

Using jQuery 2.1 on HTML5 and CSS3 compatible browsers the performance changes.

Here is the test scenario and results:

function doTest(selectorCallback) {
    var iterations = 100000;

    // Record the starting time, in UTC milliseconds.
    var start = new Date().getTime();

    for (var i = 0; i < iterations; i++) {
        // Execute the selector. The result does not need to be used or assigned
        selectorCallback();
    }

    // Determine how many milliseconds elapsed and return
    return new Date().getTime() - start;
}

function start() {
    jQuery('#stats').html('Testing...');
    var results = '';

    results += "$('#parent .child'): " + doTest(function() { jQuery('#parent .child'); }) + "ms";
    results += "<br/>$('#parent > .child'): " + doTest(function() { jQuery('#parent > .child'); }) + "ms";
    results += "<br/>$('#parent').children('.child'): " + doTest(function() { jQuery('#parent').children('.child'); }) + "ms";
    results += "<br/>$('#parent').find('.child'): " + doTest(function() { jQuery('#parent').find('.child'); }) + "ms";
    $parent = jQuery('#parent');
    results += "<br/>$parent.find('.child'): " + doTest(function() { $parent.find('.child'); }) + "ms";

    jQuery('#stats').html(results);
}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=7, IE=8, IE=9, chrome=1" />
    <title>HTML5 test</title>
    <script src="//code.jquery.com/jquery-2.1.1.js"></script>
</head>
<body>

<div id="stats"></div>
<button onclick="start()">Test</button>

<div>
    <div id="parent">
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
    </div>
</div>

</body>
</html>

So, for 100 000 iterations I get:

JS jQuery selector stats

(I have added them as img for formatting purposes.)

You can run the code snippet yourself to test ;)

Andrei Surdu
  • 2,281
  • 3
  • 23
  • 32
Vasil Popov
  • 1,210
  • 14
  • 22
  • 1
    Oh! Then looks like `.find()` does a great job. Continuing to use it. :) – Andrei Surdu Sep 19 '17 at 02:19
  • 1
    I ran this test on Android webview, this $parent.find('.child'): 2357ms (and .find('.child') ) seem to be the best while $('#parent').children('.child'): 8660ms is the worst. – The concise Oct 18 '21 at 04:22