7 ms·
JQuery implicit loops
- duopixel 14y agoThese two pieces of code should have around the same performance: $( ".widget" ).css( "color", "green" ).css( "font-size", "16px" ); $( ".widget" ).css({ "color": "green", "font-size": "16px" }) Fact is, jQuery also has to loop through the object and assign each css style declaration, so the performance is very similar. http://jsperf.com/chained-css-declarations-jquery http://jsperf.com/chained-css-declarations-jquery
- elijahmanor 14y agoNice point about the object loop. I would image though that the object would have relatively few properties whereas the number of DOM elements in the jQuery collection could vary dramatically based on the UI (think a long list of list items).
- Osmose 14y agoThat doesn't matter, though. Let's take the example above and say there's 5000 .widget items on the page. There's two properties that need to be set. Assuming jQuery works as you expect, in the first case we iterate over 5000 elements setting one attribute, then do it again, for 10000 total operations. In the second case, it iterates over 5000 elements once, but sets two attributes, which is again 10000 total operations. But this is all speculation anyway. Why not read the code? A bit of searching turns up the css function: https://github.com/jquery/jquery/blob/master/src/css.js#L102 https://github.com/jquery/jquery/blob/master/src/css.js#L102 . Interestingly, it passes a callback to something called jQuery.access. More searching finds access here: https://github.com/jquery/jquery/blob/master/src/core.js#L713 https://github.com/jquery/jquery/blob/master/src/core.js#L71... . Note line 719: If the key (which is the first argument to css) is an object, it just iterates through the object and recursively calls itself for each key-value pair in the object. Thus, passing an object to css is equivalent to calling css multiple times, ignoring small costs of re-building the callback function that css passes to access (and I'm not even sure that cost exists, I'd actually expect any decent interpreter to optimize such that re-building it is of negligible performance cost). The jQuery source code is a rather fun read, I highly recommend stepping through it from time to time. :)
- HyprMusic 14y agoIn all my days of bitching about people chaining like this, never once did it occur to me they have the same big O notation performance. I still prefer the latter style though, in my opinion it's far easier to read.
- pessimism 14y agoI’ve always questioned the sanity of the people who do something similar to the former example in d3.js; this is so much easier: http://pygm.us/IhBQwUAI http://pygm.us/IhBQwUAI.
- eamann 14y agoIn most other languages, the second form makes more sense. But jQuery is doing things under the surface that make the syntax change inconsequential. In my performance tests (Win 8, Chrome 25), the chained method actually performed faster than the object method. So while the idea of passing multiple arguments to a single function call (as opposed to making multiple function calls) might make sense for a general programming best practice, when applied to jQuery it fails.
- m0th87 14y agoThe performance implications section is completely wrong. jQuery doesn't re-query for elements on each call; the results are cached. Here's a test: http://jsperf.com/jquery-s-css-object-vs-multiple-calls http://jsperf.com/jquery-s-css-object-vs-multiple-calls My results (Chrome, Mac) are showing they have the same performance. On smaller HTML pages, multiple calls to css() actually outperformed the single call significantly (~30%).
- elijahmanor 14y agoYou are correct in that jQuery doesn't re-query the DOM for elements on each call, but what it does do is re-loop through it's internal cached collection to apply these CSS rules. The perf hit isn't noticeable when jQuery's selection (internal collection) is small. Imagine a webpage with lots of elements you want to select and then want to interact with... that is what I am trying to bring attention to.
- m0th87 14y agoWhat's your definition of a non-small jQuery selection? That sample test loops over 272 elements with no discernible performance effect.
- pixl8ed 14y agoIs it re-looping? Doesn't the .css setter return a jQuery object that is used by the next method in the chain? So it's actually only going through an implicit loop of $( ".widget" ) once?
- evan_ 14y agoIt's looping twice, because the first time you call to .css it loops through each element to add the first style, and then it loops through again on the second .css to add the second style. You could roughly replicate it with: var i, elements = document.getElementsByClassName('widget'); for (i = 0; i < elements.length; i++) { elements[i].style.color = "green"; } for (i = 0; i < elements.length; i++) { elements[i].style.fontSize = "16px"; } Two loops. The "improved" suggestion would be roughly equivalent to: var i, elements = document.getElementsByClassName('widget'); for (i = 0; i < elements.length; i++) { elements[i].style.color = "green"; elements[i].style.fontSize = "16px"; } This is one loop, but it's still O(n). If there are 100 ".widget" elements on the page, the first code does 200 writes to the style property. The second code does 200 writes to the style property. The difference in jumps and compares isn't worth thinking about when style changes are so expensive, the difference is probably immeasurable. The second version is better just because it's cleaner code, but that's it.
- jccc 14y agoThere is another explanation than the one given for seeing examples like this in someone else's code: // Indications of Confusion $( ".widget" ).each( function() { $( this ).css( "color", "green" ); }); I think this is at least as likely to be the remains of a block of code that was pared down and not (yet) re-implemented differently. The developer might have intended to return with replacement code and never did, perhaps this is an ongoing project on which you're a collaborator, perhaps the developer just forgot about it. It may still be bad code, but concluding wherever you find it that the reason is fundamental ignorance seems hasty. It will always be a struggle for me to resist the bias against Other People's Code that causes me to underestimate the developer whenever I encounter something wrong. Maybe it's a minor point, but I think this bias exists in everyone and that this is an example of it.