0
votes

I am looping over a response that I got from an ajax response, the response is an array containing 1000 objects , this response is used to created an html table with 1000 rows :

1st scenario :

    for (var i in msg.myObjects) {
    $('#mytablebody').append('<tr><td>' + msg.myObjects['item1'] + '</td><td>' + 
msg.myObjects['item2'] + '</td><td>' + msg.myObjects['item3'] + '</td><td>' + 
msg.myObjects['item4'] + '</td><td>' + msg.myObjects['item5'] + '</td><td>' + 
msg.myObjects['item6'] + '</td><td>' + msg.myObjects['item7'] + '</td> .... </tr>');
    }

Result => memory leak my RAM went to 2Go and my browser crashed

2nd scenario :

    for (var i in msg.myObjects) {
        document.getElementById('mytablebody').innerHTML = document.getElementById('mytablebody').innerHTML + '<tr><td>' + 
msg.myObjects['item1'] + '</td><td>' + 
    msg.myObjects['item2'] + '</td><td>' + msg.myObjects['item3'] + '</td><td>' + 
    msg.myObjects['item4'] + '</td><td>' + msg.myObjects['item5'] + '</td><td>' + 
    msg.myObjects['item6'] + '</td><td>' + msg.myObjects['item7'] + '</td> .... </tr>';
        }

Result => memory leak my RAM went to 800Mo and my browser crashed with a second ajax call

3rd scenario :

var stringResponse = '';
        for (var i in msg.myObjects) {
            stringResponse += '<tr><td>' + msg.myObjects['item1'] + '</td><td>' + 
        msg.myObjects['item2'] + '</td><td>' + msg.myObjects['item3'] + '</td><td>' + 
        msg.myObjects['item4'] + '</td><td>' + msg.myObjects['item5'] + '</td><td>' + 
        msg.myObjects['item6'] + '</td><td>' + msg.myObjects['item7'] + '</td> .... </tr>';
            }
document.getElementById('mytablebody').innerHTML = stringResponse 

Result => no memory leak

Ok until here I concluded that, first of all, .append() causes memory leaks, and second of all , you should never play with DOM elements inside a loop. But when I did the 4th scenario I concluded that the first conclusion was wrong (not exactly correct) and the second one is still correct.

4th scenario :

    var stringResponse = '';
            for (var i in msg.myObjects) {
                stringResponse += '<tr><td>' + replaceNulls(msg.myObjects['item1']) + '</td><td>' + 
            msg.myObjects['item2'] + '</td><td>' + msg.myObjects['item3'] + '</td><td>' + 
            msg.myObjects['item4'] + '</td><td>' + msg.myObjects['item5'] + '</td><td>' + 
            msg.myObjects['item6'] + '</td><td>' + msg.myObjects['item7'] + '</td> .... </tr>';
                }
    document.getElementById('mytablebody').innerHTML = stringResponse 

function replaceNulls(input) {
  return input != null ? input : ''
}

Result => memory leak my RAM went to 2Go and my browser crashed

My questions are:

when we call functions that occurs outside a loop , it may causes a memory leak, why ?

How can I avoid this (without removing the function or moving its processing to inside the loop) ?

1
Try pushing the html strings in an array and use Array.join() method when assigning it to the innerHTML - Sang Suantak
The issue is simply because you're making thousands of DOM operations in a loop, very quickly. Without knowing anything about the internals of the browser's JS engine, it's safe to say that's less than ideal. This is why the 3rd method you created (building the HTML string in memory, then appending it in a single DOM operation) is the best performing. This is the way all DOM appends should be done, but in most cases they are such small scale that any performance issues are not noticed. - Rory McCrossan
it may causes a memory leak, why ? There is no memory leak here.. - Keith
@RoryMcCrossan yes I agree , but i am stuck now with the 4th scenario, i can not use functions within a loop - Mehdi Souregi
The behavior you are experiencing is quite normal. You are spawning 1000 DOM elements. I dont know what your specific project needs are but I would suggest rethinking your UI by putting a button to limit the objects on the screen or using lazy loading - Kristiyan D Kovachev

1 Answers

2
votes

1000 table entries for modern web browsers should not cause any issue.

Here I'm adding 10,000 items into a table without ram problems. The reason why it's fast is because I build up the list inside a detached DOM element, then attach when done.

Your problem might be just down to DOM draw issue, the browser having to redraw on all your updates.

Another thing I noticed, for (var i in msg.myObjects) depending on what your msg.myObjects contains this is not a good thing to use. If you can use modern JS,. for (const i of msg.myObjects) is better.

var table = document.querySelector("table");

var tbody = document.createElement("tbody");

function addLine (txt) {
  var tr = document.createElement("tr");
  var td = document.createElement("td");
  tr.appendChild(td);
  td.innerText = txt;
  tbody.appendChild(tr);
}

for (var l = 1; l <= 10000; l += 1) {
  addLine("This is Line " + l + ", and some extra text");
}

table.appendChild(tbody);
<table>
  <thead><tr><th>Test</th></tr></thead>

</table>