John1984
John1984

Reputation: 987

Performance issue with $.before() on styled DOM

I've come across an interesting issue, which may be browser related (but I'm not sure about that). I'm working on a very large webpage, which is a word-processor style app. I have this structure:

<article>
    <div>...</div>
    <div>...</div>
    <div>...</div>
    ... 5000 more divs ...
</article>

When I first load the page, I have a function that does two things. First, it analyses the content of each div's html using regex and applies a class to the div if it matches a particular regex, resulting in something like this:

<article>
    <div class="type1">...</div>
    <div class="type2">...</div>
    <div class="type3">...</div>
    ... 5000 more divs ...
</article>

The second part of the function then calculates the height of each div and adds it to a counter. Once it passes a certain number, I insert a piece of HTML that serves as a page break, then rinse and repeat:

    // Pagination variables
    var document_current_page_height = 0;
    var constant_default_page_height = 1000;
    var page_number = 0;

    // Iterate over page elements
    object_range.each(function()
    {    
        // Check whether page is too long
        if (document_current_page_height + $(this).outerHeight(true) > constant_default_page_height) 
        {
            // Create page break
            $(this).before("<section contenteditable=\"false\"><h3 class=\"page-footer\">" + document_page_footer" + "</h3><figure><hr /><hr /></figure><h1 class=\"page-header\">" + document_page_header + "</h1><h2 class=\"page-number\">" + page_number + "</h2></section>");

            // Adjust variables
            page_number++
            document_current_page_height = 0;
        }

        // Increment current page height
        document_current_page_height += $(this).outerHeight(true));
    });

This code works perfectly, but here's the issue...

When run as it is supposed to be run, it takes about 2 seconds. However, if I run the same code, but skip the first part of the process (which adds classes to the divs), the code runs in 0.2 seconds.

I was further able to isolate the problem by commenting the $(this).before line of code. When this is done, both speed tests are near enough identical (within 100ms).

What I don't get, is that the $(this).before line of code does not reference the heights / styles / classes of the divs, so why the delay when the divs have a class?

Is it simply a case of the browser struggling with the divs when they have classes? Any thoughts? (I'm using Safari 9.1).

Thanks!

Upvotes: 0

Views: 27

Answers (1)

John1984
John1984

Reputation: 987

I found a solution to my issue, though it doesn't actually address why the browser behaves differently...

Instead of using $(this).before, I ended up adding the relevant $(this) to a vanilla JS array and then calling before later on:

// Pagination variables
var document_current_page_height = 0;
var constant_default_page_height = 1000;
var page_number = 0;
var page_break_array = [];

// Iterate over page elements
object_range.each(function()
{    
    // Check whether page is too long
    if (document_current_page_height + $(this).outerHeight(true) > constant_default_page_height) 
    {
        // Create page break
        page_break_array.push([$(this), page_number]);

        // Adjust variables
        page_number++
        document_current_page_height = 0;
    }

    // Increment current page height
    document_current_page_height += $(this).outerHeight(true));
});

// Create page breaks (done separately for performance benefit)
for (var i = 0; i < page_break_array.length; i++) { page_break_array[i][0].before("... HTML content ..."); }

Upvotes: 0

Related Questions