10

I have a for loop which iterates more than 10,000 times in a javascript code. The for loop creates and adds < div > tags into a box in the current page DOM.

for(i = 0; i < data.length; i++)
{
    tmpContainer += '<div> '+data[i]+' </div>';
    if(i % 50 == 0) { /* some delay function */ }
}
containerObj.innerHTML = tmpContainer;

i want to put a delay after every 50 < div > tags so what will be the code at the place of

/* some delay function */

because its taking too much time to load all 10,000 < div > tags. i want to update the box in chunks of 50 < div > tags.

thanks in advance.

Kasun Kodagoda
  • 3,956
  • 5
  • 31
  • 54
Vinay Jeurkar
  • 3,054
  • 9
  • 37
  • 56

5 Answers5

16

There's a handy trick in these situations: use a setTimeout with 0 milliseconds. This will cause your JavaScript to yield to the browser (so it can perform its rendering, respond to user input and so on), but without forcing it to wait a certain amount of time:

for (i=0;i<data.length;i++) {
    tmpContainer += '<div> '+data[i]+' </div>';
    if (i % 50 == 0 || i == data.length - 1) {
        (function (html) { // Create closure to preserve value of tmpContainer
            setTimeout(function () {
                // Add to document using html, rather than tmpContainer

            }, 0); // 0 milliseconds
        })(tmpContainer);

        tmpContainer = ""; // "flush" the buffer
    }
}

Note: T.J. Crowder correctly mentions below that the above code will create unnecessary functions in each iteration of the loop (one to set up the closure, and another as an argument to setTimeout). This is unlikely to be an issue, but if you wish, you can check out his alternative which only creates the closure function once.

A word of warning: even though the above code will provide a more pleasant rendering experience, having 10000 tags on a page is not advisable. Every other DOM manipulation will be slower after this because there are many more elements to traverse through, and a much more expensive reflow calculation for any changes to layout.

David Tang
  • 92,262
  • 30
  • 167
  • 149
  • 1
    That'll work, but two comments: 1. It unnecessarily creates a **new** function every time you reach 50 divs. That's 199 unnecessary functions. Probably okay, but still, avoidable. 2. It's more efficient to build HTML up in an array of strings, and then use `a.join("")` to create one big string when you're done, than to use string concatenation to build up the HTML. – T.J. Crowder Feb 06 '11 at 10:24
  • @T.J. you're right about both those points, but I didn't bother for the sake of simplicity: 1. Function creation is rarely a performance issue, especially when your bottleneck is the DOM, 2. string concatenation is only a problem on IE, and often faster in other browsers, but even for IE, since I'm resetting `tmpContainer` to an empty string, the strings never become large ;) – David Tang Feb 06 '11 at 10:33
  • @Box9: Just saw it: **`document.write`**?!?! That flatly will not work. `appendChild`, etc., is fine. – T.J. Crowder Feb 06 '11 at 11:20
  • @T.J. well it will *work*, but it'll just overwrite the page you had, so it probably won't work *as expected* ;) I hope it was clear that it merely indicates the use of the variable `html` rather than `tmpContainer`. – David Tang Feb 06 '11 at 12:33
  • @Box9: Interesting interpretation of "work". ;-) I'd remove it as completely misleading and just go with a comment "use `html` here to create elements". By the way, I was wrong before, it's ~398 completely unnecessary functions (you're recreating the thing that *creates* the closures, which there's even less need for than the other). Also, unless it happens that `data.length % 50 == 0`, this will either fail to output the last 1-49 or at least require duplicated code to do so. Instead: http://pastie.org/1533736 This is **all** by way of giving a good answer, not giving you a hard time. – T.J. Crowder Feb 06 '11 at 12:46
  • @T.J. I added your suggestions to my answer. I still disagree about how significant the extra functions are, but I linked to your code anyway. No hard time given, thanks for the input. – David Tang Feb 06 '11 at 22:15
  • @Box9: Nice to interact with someone who *isn't* insanely touchy. :-) Best, – T.J. Crowder Feb 06 '11 at 22:24
  • The output matters folks, so problem is solved with all of your views. thanks for that... – Vinay Jeurkar Feb 07 '11 at 03:19
  • hey i have another too... can you please help with that too? http://stackoverflow.com/questions/4917790/mootools-i-want-to-implement-architecture-similar-to-big-pipe-in-facebook – Vinay Jeurkar Feb 07 '11 at 03:20
3

You could use the window.setTimeout function to delay the execution of some code:

if(i % 50 == 0) {
    window.setTimeout(function() {
        // this will execute 1 second later
    }, 1000);
}

But your javascript will continue to execute. It won't stop.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
1

I'd break out the code creating the divs into a function, and then schedule execution of that function periodically via setTimeout, like this:

function createThousands(data) {
    var index;

    index = 0;
    doAChunk();

    function doAChunk() {
        var counter;

        for (counter = 50; counter > 0; --counter) {
            // Are we done?
            if (index >= data.length) {
                // Yup
                return;
            }

            // ...create a div...

            // Move to the next
            ++index;
        }

        // Schedule the next pass
        setTimeout(doAChunk, 0); // 0 = defer to the browser but come back ASAP
    }
}

This uses a single closure, doAChunk to do the work. That closure is eligible for garbage collection once its work is done. (More: Closures are not complicated)

Live example

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

it takes much time because the reflows. you should create a document fragment and then adding the brats.

When does reflow happen in a DOM environment?

Javascript Performance - Dom Reflow - Google Article

sleeping will not solve your problem

on the other hand, you creating a string containing the innerhtml and the add to innerhtml. the string stuff really dont needs a big performance, but when you execute the .innerhtml command, it starts a process, which parse your string and creating elements and appending them. you cant interrupt or add a delay.

the innerhtml process cannot be sleeped or interrupted.

you need to generate the elements one by one, and after 50 elemnts added, create a settimeout delay.

var frag = document.createDocumentFragment();

function addelements() {

   var e;
   for(i=0;i<50;++i) {
       e = document.createElement('div');
       frag.appendChild(e);
   }
   dest.appendChild(frag);
   window.setTimeout(addelements,1000);

}
Community
  • 1
  • 1
Gergely Fehérvári
  • 7,811
  • 6
  • 47
  • 74
-1

Here is the real trick to put a delay in javascript without hanging the browser. You need to use a ajax function with synchronous method which will call a php page and in that php page you can use the sleep() php function ! http://www.hklabs.org/articles/put-delay-in-javascript

Kaushik
  • 1
  • 2
  • 2
    Note that [link-only answers](http://meta.stackoverflow.com/tags/link-only-answers/info) are discouraged, SO answers should be the end-point of a search for a solution (vs. yet another stopover of references, which tend to get stale over time). Please consider adding a stand-alone synopsis here, keeping the link as a reference. – kleopatra Oct 05 '13 at 10:24