This is a slightly edited version of the post here by @michealhall
Though it is originally about a specific example, the logic seems sound and if you look at the code you’ll understand what it’s about.
Feel free to intervene if you’d like to re-arrange the text or feel something is missing.
Is there a reason you are not caching your jQuery selectors?
Re-selecting inside of a loop (whether with jQuery or using something like document.getElementsByClassName() is very in-efficient, as it has to be re-done with each iteration off the loop.,
For example:
for(var i = 0 ; i < 63 ; i++){
$('.canvas').append('<ul></ul>');
}
for(var i = 0 ; i < 57 ; i++){
$('ul').append('<li></li>');
}
Inside of every loop iteration, you are re-selecting the same elements.
Not only that, but in the ul example, you are selecting all uls on the page, adding just one element to each one, then repeating the process … 57 times!
That’s a classic jQuery issue, but easily solved:
// SELECT IT ONCE, THEN MODIFY IT IN THE LOOP.
const $canvas = $( '.canvas' );
for(var i = 0 ; i < 63 ; i++){
$canvas.append('<ul></ul>');
}
That way you aren’t re-selecting the element 63 times in that loop.
However, even that is not “best practice”.
Because you are also updating the DOM 63 times as well (not to mention all of the li updates in the next loop).
Updating the DOM is slow and calculation intensive (triggering layout reflows and such).
What you usually want to do is build your DOM fragments or HTLM string and then update the DOM only one time.
const $canvas = $( '.canvas' );
const $parent = $canvas.parent();
$canvas
.detach()
.append( new Array( 64 ).join( '<ul></ul>' ) )
.find( 'ul' ).append( new Array( 58 ).join( '<li></li>' ) )
.end()
.appendTo( $parent );
Above, you select the .canvas element one time. You also get a reference to its parent container so that you can remember where it was in the DOM (we’ll need this later).
Next we use a bit of jQuery method chaining to keep things simple and clear and not have to keep re-typing $canvas. (Method chaining is actually a Javascript feature that jQuery makes good use of). Most methods in jQuery return this, which is the jQuery object/collection you are working with. That way you can simply add another method call onto the end of the last.
What is Chaining in jQuery?
Learn jQuery by examples and how to tips. Know jQuery functions, tutorials, jQuery UI, Selectors, Ajax, Plugins, jQuery interview questions and codes.
After you select $canvas and save reference to its parent in the DOM, then you .detach() the $canvas from the DOM. This allows you to work on it without updating the DOM on every change. It’s much faster than working directly in the DOM.
Then you use the .append() method to insert a string of HTML into the $canvas. In this case, we’re using the new Array() syntax to supply a length of the array and then the join method with a separator string of an empty list. The join method then builds the list for us with no loop needed!
Next we find all of the uls we just appended to the $canvas and repeat the new Array() trick with the number of lis needed. One thing to know about jQuery is that, when you make a selection, such as $( ‘ul’ ) or $canvas.find( ‘ul’ ) and then use a method like .append(), jQuery will perform the operation on all elements selected. So there is no need for us to create a loop here or to use jQuery’s .each() method. The library does that for us.
Finally, we use .appendTo() to put the $canvas back in the DOM.
The result is the same, but now we did only one DOM selection for $canvas. We then detached it from the DOM and worked on it where it is much faster and efficient to update and finally re-inserted it into its parent - again only one DOM update, instead of …at least 64*57 updates previously!
The things mentioned about updating the DOM, selecting elements, etc. apply to all Javascript, not just jQuery.