0
\$\begingroup\$

I'm thinking about DOM modification performance.

In a perfect way, we alter each element but DOM modification is really heavy and alter many elements at same time froze the browser. I didn't make any performance tests but I want to know if the second way can be more powerful.

In my head, the first way will ask the browser to refresh the display for each div. So logically, with the second way, the browser will refresh only once per injection. Is that correct?

HTML:

<body>

<header></header>

<div id="container">
    <div id="test1" alt="test1alt"></div>
    <div id="test2" alt="test2alt"></div>
    <div id="test3" alt="test3alt"></div>
    <div id="test4" alt="test4alt"></div>
    <div id="test5" alt="test5alt"></div>
    <div id="test6" alt="test6alt"></div>
    <!--[...200 more div]-->
</div>

</body>
<script>

JS first way: alter each element

$(document).ready(function() {
    setInterval(function() {
        var value;

        $('#container div').each(function() {
            if(randNum(0, 10) != 1) {
                return true;
            }

            value = randString();

            if($(this).attr('alt') != value) {
                $(this).attr('alt', value);
            }
        });
    }, 100);
});

JS second way: rewrite base HTML and inject when modified

var myDOM = {};

function domConstruct(obj) {
    $('> div', obj).each(function() {
        myDOM[$(this).attr('id')] = $(this).attr('alt');
    });
}
function domAlter(id, value) {
    if(myDOM[id] == value) {
        return;
    }

    myDOM[id] = value;

    return true;
}
function domUpdate(obj) {
    var buf = '';

    $.each(myDOM, function(id, value) {
        buf += '<div id="'+id+'" alt="'+value+'"></div>';
    });

    obj.html(buf);
}

$(document).ready(function() {
    domConstruct($('#container'));

    setInterval(function() {
        var inject = false;

        $.each(myDOM, function(id) {
            if(randNum(0, 10) != 1) {
                return true;
            }

            if(domAlter(id, randString())) {
                inject = true;
            }
        });

        if(inject) {
            domUpdate($('#container'));
        }
    }, 100);
});

JS Utils funcs:

function randNum(a, b) {
    var argc = arguments.length;

    if(argc == 1) {
        return 1;   
    }

    if(argc == 0) {
        a = 0;
        b = 2147483647;
    }

    return Math.floor(Math.random() * (b - a + 1))+a;
}
function randString() {
    return Math.random().toString(36).replace(/[^a-z]+/g, '');
}
</script>
\$\endgroup\$
2
\$\begingroup\$

If you have performance issues, then I believe you should first try and profile your script, to identify which function(s) run slowly. There are profilers embedded in most scripting consoles.

Regarding your question: since your code should not trigger any repaint, I believe that method 1 would be fine. Unfortunately, I have not been able to reproduce the issue on my machine, so cannot confirm this answer.

To improve performance, I suppose you could try the following:

  • Rather than using setInterval, consider chaining setTimeout calls, so that the browser remains responsive.
  • Try and remove your library, to use native Javascript. It looks like you do not need anything more than getElementById, getElementsByTagName, getAttribute and setAttribute - so should be able to safely eliminate any library overhead.
  • Possibly cache the retrieval of all the div, as you only need to perform it once.

So basically, try and run the following (untested) on window.onload:

function update() {
    var delay = 100;
    var container = document.getElementById("container");
    var divs = container.getElementsByTagName("div");

    function updateDivs() {
        for (var ii = 0; ii < divs.length; ii++) {
            var div = divs[ii];
            if (randNum(0, 10) == 1) {
                var value = randString();
                if (div.getAttribute("alt") != value) {
                    div.setAttribute("alt", value);
                }
            }
        }
        setTimeout(arguments.callee, delay);
    }

    updateDivs();
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ My bad, I poorly explained. The first time I posted my question, I've wrote a pure theory code (not working), and elclanrs asked me to edit my post with complete code. There is no code to optimize because the previous code illustrate the theory. When I woke up I asked myself : "Which way is better when we alter the DOM relatively frequently (0, 10, 20, 100... times per interval lower than 500ms) ?" In the previous code (first way), the attributes are probably modified many times per interval, so if 50 div are modified, does this trigger 50 repaint ? \$\endgroup\$ – Lossius Jul 24 '16 at 1:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.