Reputation: 912
I've got a for
loop in which I am appending rows to a table
. Although I append each tr
one at a time in the loop, the browser does not render any of them until the loop is finished.
At first, I thought it might be the browser rendering too quickly for me to notice, but after increasing the number of rows to, say, 10000, there's a significant slowdown, then the entire table shows at once.
Link: http://jsfiddle.net/xyan/ad2tV/
Increment counter
to increase the number of rows.
Also, if you change counter
to 3 (or another small number) and uncomment the alert()
, it will pause the loop and show each row being added one at a time.
HTML:
<div></div>
Javascript:
var table = $('<table />').appendTo($('div'));
var counter = 1000;
var html = [];
var j = 0;
for (var i = 1 ; i < (counter + 1) ; i++) {
html[j++] = '<tr>';
html[j++] = '<td>'+i+'-1</td><td>'+i+'-2</td><td>'+i+'-3</td>';
html[j++] = '<tr>';
table.append(html.join(''));
//alert('pause');
html = [];
j = 0;
}
CSS:
table td {
padding: 3px;
border: 1px solid red;
}
Note:
I've found a way to force the loop to slow down, allowing the rows to be added one at a time.
Link: http://jsfiddle.net/xyan/8SCP9/
var html = '';
var numbertorun = 15;
var delay = 500;
(function loop (i) {
setTimeout(function () {
html = '<tr><td>'+i+'-1</td><td>'+i+'-2</td></tr>';
$('table').append(html);
if (--i) loop(i);
}, delay)
})(numbertorun);
So I guess my question isn't how to do this, but why the rows aren't inserted one at a time in the original for
loop.
Upvotes: 4
Views: 1589
Reputation: 30511
I'm guessing some background is needed to understand this question.
Each time you add a new row to the table in your webpage, your script will alter the model of your document in your browsers memory. The API you are using for this is called DOM (Document Object Model).
An individual update to DOM doesn't always necessarily mean that a page will be redrawn. It is up to the browser to decide, when a given set of DOM alterations will cause the browser to re-render the page.
I don't know for fact, but I'm guessing that browsers typically update views perhaps somewhere around 40-60 times per second. The thing is this: if your table printing takes less time than 1/60th of a second, you don't get to see the partial updates.
By adding a timer you of course can slow down the progress of creating the table. As you perceived, this will allow you to see the page redrawn at different points during the for loop.
If you wish to force browser to redraw the UI, there are some JavaScript hacks you could try applying. One such hack for instance is documented in Ajaxian: Forcing a UI redraw from JavaScript.
If you deliberatively wish to run your program slowly and add rows slowly, say one row per second, while potentially doing some other stuff with JavaScript at the same time, you need to run the loop either by triggering new iterations somehow or by using another (JavaScript) thread.
A schematic example of using setTimeout
to slow down printing (prints out 1 row per sec, just tweak second parameter in window.setTimeout
to change delay):
var table = $('<table id="table1"/>').appendTo($('div'));
var i = 0;
var counter = 1000;
function addRow() {
table.append('<tr><td>'+i+'-1</td><td>'+i+'-2</td><td>'+i+'-3</td></tr>');
i++;
if(i<counter) {
window.setTimeout( addRow, 1000 );
}
}
addRow();
Upvotes: 2
Reputation: 33621
Each time an element is added to the page, the browser needs to redraw the entire page. In rendering terms, this is an extremely intensive process and is quite slow. So if you make small changes little by little that will make the page appear really slowly. What the browser is doing is to group the little changes into big changes. The end result is that the page will render much more quickly in aggregate.
The browser is doing this:
http://www.tvidesign.co.uk/blog/improve-your-jquery-25-excellent-tips.aspx#tip6
Upvotes: 0
Reputation: 791
jQuery append method is similar to javascript appendChild method. Both these methods traverse through the DOM and insert the element at the end of the parent node. This task takes time and doing this inside a Loop will cause frequent changes in DOM Structure which the DOM will not able to replicate. So by inserting your rows using settimeout gives the browser ample time to re-load the content. Hence you see the one by one insertion of rows in the second approach.
Upvotes: 0