user967451
user967451

Reputation:

What is the fastest way to build HTML from JavaScript?

I am working on a website that uses infinite scroll. There is a function called is_element_in_view() that gets executed on these 3 events:

scroll
load
resize

The function does exactly what it's called, it checks to see if an element with a loading gif image is in view and if so it fires an ajax request to get content from the server.

The server sends back a json object that looks like this:

    [{
        "url": "\/embed\/182926\/some-slug",
        "thumb": "http:\/\/cdn.site.com\/91\/26\/a62c1ad74327321dab78bb194c130da5.jpg",
        "type": "video",
        "is_original": false,
        "is_prank_news": false,
        "title": "Hello World",
        "description": "\t<p>Enjoy this video!<\/p>",
        "teaser": "Click Me!",
        "finder": "Found by <strong>Jim<\/strong> yesterday",
        "likes": "2 likes",
        "ad_img": null,
        "media_stats": "<div class=\"media-status\">2000 views<\/div>"
    },
    more objects...]

There's only one object in this response for clarity sake but in reality I get back 20. This is how I'm building out the html from the json data:

$.ajax({
    url: '/some/ajax/url',
    type: 'get',
    data: 'somedata',
    dataType: 'json',
    success: function(response) {

        if(!$.isEmptyObject(response)) {

            for(var i = 0; i < response.length; i++) {

                if(response[i]) {
                    var item = response[i];
                    var title = item.title.replace(/\\"/g, '"');

                    var media_label = '';                   
                    var item_description_teaser = '';
                    var likes = '';
                    var ad_image = '';
                    var media_stats = '';

                    if(item.description) {

                        // description
                        item_description_teaser = '<div class="description">' + item.description.replace(/\\"/g, '"');

                        // teaser
                        item_description_teaser += (item.teaser) ? '<a href="'+ item.url +'" class="teaser">'+ item.teaser.replace(/\\"/g, '"') +'<img src="images/teaser-arrow.png" alt="" /></a></div>' : '</div>';
                    }

                    // media label
                    if(item.type == 'article' && item.is_prank_news || item.is_original && item.is_prank_news) {
                        media_label = '<span class="media-label prank-news-network">Prank</span>';
                    }
                    else {
                        if(item.type == 'article') {
                            media_label = '<span class="media-label article">Article</span>';
                        }
                        else if(item.is_original) {
                            media_label = '<span class="media-label original">Original</span>';
                        }
                    }

                    // likes
                    if(!settings.hide_likes) {
                        likes = '<span class="likes">' + item.likes + '</span> | ';
                    }

                    // ad image
                    if(item.ad_img) {
                        ad_image = '<img src="'+ item.ad_img +'" alt="" class="ad-img" />';
                    }

                    block += '<article class="block">' +
                                '<div class="inner-left">' +
                                    media_label +
                                    '<a href="'+ item.url +'" title="" class="thumb">' +
                                        '<img src="'+ item.thumb +'" alt="" width="198" height="111" />' +
                                    '</a>' +
                                '</div>' +
                                '<div class="inner-right">' +
                                    '<a href="'+ item.url +'" title="" class="title">' +
                                        title +
                                    '</a>' +
                                    item_description_teaser.replace(/\\"/g, '"') +
                                    '<div class="media-stats">' +
                                        likes +
                                        '<span class="finder">'+ item.finder.replace(/\\"/g, '"') +'</span>' +
                                    '</div>' +
                                    ad_image +
                                '</div>' +
                                item.media_stats +
                            '</article>';

                }
            }

            $('#content').append('<div class="page page-'+ page_num +'">' + block + '</div>');

            // update page count
            page_num++;

            // clear previous listings
            block = '';
        }
        else {
            $('#content').append('<div class="page page-1"><p class="nothing-to-show">Nothing found...</p></div>');
        }
    },
    error: function() {
        alert('error');
    }
});

As you can see I put everything in one giant string stored inside the variable block. I append data to this string with every loop and append it to the page outside the loop at the end.

I feel like there is a faster way to build html from js. I read somewhere a while ago that building giant strings like I'm doing isn't as efficient as some other method the article described that I forgot. So what's the faster way to do this?

Upvotes: 2

Views: 203

Answers (3)

jorgehmv
jorgehmv

Reputation: 3713

Adding html elements to the DOM represents a big performance penalty so it is better to create a big string and append it at the end, this post explains it really well

For most of your uses, the method of creating one really long string and appending it at the end will be the best choice, as it makes the best use of the trade offs of code legibility, ease of programming, and speed.

Upvotes: 0

honyovk
honyovk

Reputation: 2747

You could have your server return the values already marked-up in HTML, then:

$('#content').append( response );

You can then handle all of your looping and filtering server side, cutting down on the amount JS in your document.

Upvotes: 0

MaxArt
MaxArt

Reputation: 22637

Store the blocks in an array say blocks, then

$('#content').append(blocks.join(""));

Edit: that wasn't what the OP wanted. I guess the problem is appending the stuff each time the event is triggered.

I'd say to create a DocumentFragment, put the new stuff in it, then appending to $("#content"). Unfortunately, DocumentFragments don't support innerHTML.

So, create a dummy element, fill it and then put its child nodes into the container:

var dummy = $("<div>").html(block), content = $("#content");
$.each(dummy.children(), function(i, c) {content.append(c);});

Upvotes: 2

Related Questions