The Situation:
I've been working recently with trying to create DIV's on the fly. i.e. a user clicks on an element, and that generates the innerHTML of some DIV on the page.
For instance, I might have:
Clicking on the Generate link would set the innerHTML of the div named theDiv to be set to some arbitrary string (lets say its the string below):
<p>Hello World for the first time.</p>
The Problem:
The problem I am having is when I try to write the "Hello World" string to the innerHTML several hundred/thousand times. Basically I loop through a list, and write the "hello world" top a string until the loop is done, and then I write it out to innerHTML. This causes the browser to slow down and become unresponsive for a few seconds. The greater the number of lines the longer the pause/slowdown.
My Question:
Is there a faster way to write to the document? Using the DOM is too slow, and I don't need to programatically access any of these newly created nodes so I don't think that will help any. I haven't seen chunking the data out to innerHTML make much of a diffrrence (i.e. writing to innerHTML every X number of lines) from my brief tests either.
Thanks for the response Kor. I've read that innerHTML was usually faster than the DOM, but just to check I whipped out the following test case:
HTML Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><title>JS Test</title><script type="text/javascript">
function makeDiv(oParent){
var d1=new Date().getTime();
for(var i=0;i<1300;i++){
var oP=document.createElement("p");
var oB=document.createElement("b");
var oBR=document.createElement("br");
var oA=document.createElement("a");
var oI=document.createElement("img");
oI.src='nc.gif';
oP.appendChild(oB);
oP.appendChild(oBR);
oP.appendChild(oA);
oP.appendChild(oI);
oB.appendChild(document.createTextNode("Text for testing. Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum. Para #" + (i + 1)));
oA.appendChild(document.createTextNode("Text for testing. Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum. Link #" + (i + 1)));
oParent.appendChild(oP);
}
var d2=new Date().getTime();
alert(d2-d1);
}
function makeDiv2(oParent){
var d1=new Date().getTime();
var str=new String();
for(var i=0;i<1300;i++){
str+='<p><b>Text for testing. Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum. Para # '+(i+1)+'</b><br><a> Text for testing. Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum.Lorem Ipsum. Link # '+(i+1)+'</a><img src="nc.gif"></p>';
}
oParent.innerHTML=str;
var d2=new Date().getTime();
alert(d2-d1);
}
</script></head><body><h3>Div is below</h3><p><a href="#" onclick="makeDiv(window.document.getElementById('me'));">Start DOM</a></p><p><a href="#" onclick="makeDiv2(window.document.getElementById('me'));">Start innerHTML</a></p><div id="me"></div></body></html>
The results were as follows:
Using the DOM, the execution times were: 3725ms,3690ms,3643ms, and 3530ms.
Using innerHTML the execution times were: 1538ms,1576ms,1488ms, and 1518ms
So this test bears out that innerHTML is usually faster. I don't use the DOM that much so I'm having to assume that code I snagged is the "correct" way to do it using the DOM (and also the most efficient)
If you have tested, that it should be so... In that case, the sigle thing that could speed a little bit the process is to loop in reverse. It will speed the process about 2 times. Counting down to 0 is faster that counting up to a number of iteration.
for(var i=1299;i>=0;i--){
...
}
You can also use the flipped loop with reverse count, using do-while instead of a for() loop
the fastest way to loop seems to be the so called "Duff's" method... Which is a combination of flipped reverse loop and switch/ cases but the disadvantage is that you should write 1300 case lines...
This causes the browser to slow down and become unresponsive for a few seconds.
I am not sure from your coment whether it is the innerHTML that is the problem, or the loop creating the string.
If it is the loop creating the string, then as well as Kor's more efficient loop strategies, you should note that concatenation of strings can also be quite slow
i.e. str=str+"another string"
The alternative is to add all the strings to an array, and then join the array.
var aStr=new Array();
aStr.push("another string");
aStr.push("another string");
aStr.push("another string");
var sString=aStr.join("");
Thanks all for replying. I've been doing some testing and here are the results so far.
*( '++' and '--' is the increment method used in a for loop, going to try do...while next. It looks like one of the things that really has an affect on the speed is the existence of images in the created element. Other than not using images, setting the images as the background of a DIV, and then making that div be the same size as the full image seems to have the most speed increase. Once again however, using innerHTML, seems to give a pretty decent speed increase. I'm going to run some more tests using the other tips I've gotten from the forum. Thanks again for all of your help. The code is below if you would like to repeat the tests.)
DOM: ++image: 6091 ms
DOM: ++image(as background): 1245 ms
DOM: ++No Image: 1416 ms
DOM: --image: 5811 ms
DOM: --image(as background): 1232 ms
DOM: --No Image: 1091 ms
innerHTML: ++Image: 2630 ms
innerHTML: ++Image (as background): 334 ms
innerHTML: ++Image (no image): 359 ms
innerHTML: --Image: 2540 ms
innerHTML: --Image (as background): 341 ms
innerHTML:--Image (no image): 365 ms
(I have to post the actual code in another post due to size restrictions
After looking at everything it has *really* sped up, well I should say the time it takes the functions to excute and be timed has sped up.
My bottleneck is now the time it takes the browser to render the information.
Basicall i write this information (via innerHMTL or the DOM) to a div who has its display style set to "none".
Once the data has been pulled, and the div has been populated, i just set the style to be "block". This has the effect of making all of the newly generated HTML be visible. From all my testing, this is the bottleneck. The redering engine/javascript get so bogged down that the actual timer stops while the HTML is rendered. So when all is said and done, my timer t ells me that 1200 ms have elapsed, but measuring with a watch, tells me that approximately 52 seconds have gone by since the browser locked up/bogged down/stopped responding after my click.
Does anyone have any experience with the actual way the browser handle the rendering calls?
I've got a few options I can explore (chunking the data to the layer every few seconds, a more>>> button, etc.)
Bookmarks