views:

90

answers:

3

I've read that javascript gets significant performance benefits from modifying off-dom. Earlier today, I was reading the clone documentation:

"Note that when using the .clone() method, we can modify the cloned elements or their contents before (re-)inserting them into the document."

Is the implication then that if I have 1,000 LI's and I want to make a change across all of them, the most efficient method would be to clone it, modify the clone, destroy the original, and place the clone?

How would you go about making this modification in the most efficient way?

+4  A: 

Actually, the implication is that it would be more efficient to modify cloned elements before inserting them into the DOM than to insert the cloned elements into the document and then modify them. Whether or not clone-modify-replace is more efficient than simply modifying the elements in-place will likely depend a lot on what modifications you intend to make... As always, profile your code and then choose the option that best meets your needs based on real data.

...And while you're at it... You can "detach" a DOM element directly: just call removeChild() (or, since you're using jQuery, detach()) - the element will still exist as long as you retain a reference to it, and can be re-inserted after you're done making modifications.

...Oh, and regardless of which technique you end up using, you'll almost certainly see better results from removing the parent UL than from removing each of the 1K child LI elements, one at a time...

Shog9
Like this? --------- var $ul = $(ul);$ul.removeChild();$ul.appendTo("body");
Matrym
@Matrym: oh, right, jQuery... Just use [`remove()`](http://api.jquery.com/remove/) then: `var ul = $("ul").remove(); /* modifications to children of ul ... */ ; ul.appendTo("body");` Note that jQuery works just fine on detached elements - you can still search and filter the descendants of the list in the normal fashion.
Shog9
`.remove()` deletes jQuery data associated with the nodes, such as events. It would make more sense to use `.detach()`, as I've suggested in my answer.
Mewp
@Mewp: good point.
Shog9
+1  A: 

There's one more efficient method: .detach() them from the tree, modify, and then reinsert.
However, if you only modify properties of the DOM objects, and not read them, you shouldn't trigger a reflow (which is the slow operation) anyway, at least not in firefox (from what I've read). Though detaching them, and then reattaching makes sure that there are at most two reflows.

Mewp
+2  A: 

The detach() method is the method designed for exactly what you're trying to do:

http://api.jquery.com/detach/

Edit: It's worth a mention that everyone do their own profiling/tests, which is good, common sense advice. Plus it's fun to see the ridiculous performance gains you'll get. :)

My rule of thumb is this: If you're doing manipulations on many elements that involves adding or removing or moving elements around, you should absolutely use .detach(), if you're doing something like addClass, don't use detach.

If you're unsure about specific manipulations or how many qualifies as 'many', you should run a test.

Here's a simple comparison I made in this question's debate: http://jsbin.com/uwode3/5 vs http://jsbin.com/uwode3/4

Mark
`detach()` is just a wrapper for `remove()` with an extra parameter to retain jQuery data. http://github.com/jquery/jquery/blob/master/src/manipulation.js#L298 How does this answer OP's question about performance?
patrick dw
@patrick Oh, I didn't realize that but basically everyone else has mentioned .detach() already. The .detach() method assists in making DOM manipulations off DOM, the same idea as .clone(). Only .detach() is safer/lessbraincycles to use than .remove().
Mark
@patrick, also check out the 1.4 release notes, which mention this exact usecase for detach. http://jquery14.com/day-01/jquery-14 search for detach.
Mark
@Mark: Just a hint: if you want to create JavaScript performance test cases easily, just use [jsPerf](http://jsperf.com/).
Mathias Bynens