Does jQuery use create document fragment inside each loops?
Asked Answered
T

3

7

So I've read that jQuery uses document fragments internally to make rendering faster. But I am wondering if anyone knows if jQuery would use createDocumentFragment in this situation where I'm appending img elements to the DOM using the each loop?

var displayArray = []; // Lots of img elements

$.each(displayArray, function()
{
    $('#imgSection').append(this);
});

Or would I need to use this code in order to reduce the number of browser reflows?

var displayArray = []; // Lots of img elements
var imgHolder = $('<div/>');

$.each(displayArray, function()
{
    imgHolder.append(this);
});

$('#imgSection').append(imgHolder);

Also, the displayArray is populated by other code, not shown here, that creates img elements based off of paths in a JSON file.

Thank you for any advice.

Taste answered 30/1, 2013 at 22:58 Comment(8)
.append will directly add the element to the other element. I don't see how a document fragment could even work here.Phlogistic
@FelixKling The idea here is to reduce the number of times the browser has to reflow the screen. I was just wondering if jQuery does that internally or not.Taste
Yes, I understand that, but in this case you are iterating over an array of DOM elements lets say and in each iteration your are adding an element to an existing element in the tree. There cannot be a middle step where jQuery is using a document fragment. You have to take of avoiding reflows yourself.Phlogistic
@FelixKling Ahh... that makes more sense now. Thank you.Taste
If you have "lots of img elements", the browser will rather be troubled with image loading than with reflowing.Copal
@Copal Already thought of that. The images preload and are not put in the DOM until they have a width > 0.Taste
@Freethinker Just wondering why preloading images then put them in the DOM is better than user watch them loading in queue (at least user can see the loading progress)?Parlous
@Parlous The application I was doing this for is an interactive virtual tour and I needed to download at least 6 of the images before allowing the user to interact with it. Otherwise, they might get confused if they we're trying to use it before the images were downloaded. While this was happening, I did use a loading progress screen.Taste
F
8

Why all the looping to add elements?

$('#imgSection').append("<div>" + displayArray .join("") + "</div>");

Okay so it is elements.

The quickest way is going to be using append with the array itself.

$("#out").append(elems);

other option using one div to append is

var div = $("<div/>").append(elems);
$("#out").append(div);

BUT appending a lot of images at once is going to be bad unless they are preloaded. That will be a bunch of http requests being queued up.

jsPerf test cases

Flick answered 30/1, 2013 at 23:2 Comment(9)
displayArray might contain DOM elements or jQuery objects.Equity
Blender is right, my displayArray is populated by some other code, not shown here, that takes image paths from a JSON file and creates img elements.Taste
you can't call .append() with an array like that.Artist
@Artist Really? Would you like to make a bet on that? jsfiddle.net/A3TM7Flick
@Flick Thanks for the test cases, that really helps. And yes the images are preloaded and preloaded one at a time, they're big images for a slide show.Taste
according to this blog article - bennadel.com/blog/… - jQuery will use a doc fragment if you pass an array of elements to .append()Artist
@Artist Thank you! That's the kind of article I was looking for. Good to know.Taste
Hi @Flick , One thing that I don't understand about preloading. When you preload lots of images, doesn't that needs the same bunch of http requests? When do you do preloading, right after the page loading?Parlous
@Parlous Yes it still needs the requests, but it you want it to all appear at once, than you would need to preload. If you don't you would have the empty spaces.Flick
A
8
  1. No, if you use $.each() then jQuery won't use a DocumentFragment - jQuery has no way of knowing what you're going to do inside the loop and each iteration is independent.

  2. The point of the document fragment is that you don't have to wrap all your new elements up in a wrapper element as you've done in your second example to limit the reflows.

  3. jQuery apparently will use a document fragment if you pass an array of elements directly to .append() instead of iterating over them yourself.

Artist answered 30/1, 2013 at 23:23 Comment(8)
I think "if your elements need a common parent[...]" is an important point. Thanks for pointing that out. Confirmed my thinking.Whitmer
"the fragment can contain multiple elements all of which will be inserted at the required point."... Are you saying that those multiple elements can be attached at different parents in one go? How do you do that?Overcheck
@RobertSiemer no, I'm not saying that at all. A document fragment is just a way of inserting a whole set of elements to the DOM in one place and in a single operation.Artist
Then the sentence “If your elements need a common parent then you don't need document fragments.” does not make much sense.—This is the only thing a document fragment is good at: attaching to a common parent. And if your elements don’t need a common parent (i.e. should go to different parents), you are out of luck with atomic operations with document fragments or any other method I know of.Overcheck
@RobertSiemer I can maybe rephrase that, but bear in mind I wrote it 7 years ago. I think I was trying to say that you don't need a fragment to perfom an atomic insert if the elements are the whole set of elements that are going to share a newly inserted parent.Artist
Thanks for clearing that up. My knowledge would not be on the level it is now without this q/a and the dialogue we just had.Overcheck
@Whitmer ...some time passed, but your comment indicates a thinking which might had taken a different turn with the other comments on this answer now.Overcheck
@RobertSiemer Valid! Thanks for leading me back to the topic!Whitmer
C
0

If you really care about reflows (and have noticed the displaying to be slow), you can hide and show the image-holding element:

var displayArray = […]; // Lots of img elements
var holder = $('#imgSection').hide();
for (var i=0; i<displayArray.length; i++)
    holder.append(displayArray[i]);
holder.show();
Copal answered 30/1, 2013 at 23:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.