3

I have made the following program on jQuery:

$(document).ready(function(){
    var k = 0;
    setTimeout(function(){alert("Hello")},500);
    for (var i = 0; i < 5000; ++i) {
        ++k;
        $('.inner').append('<p>Test</p>' + k.toString());
    }
});

I expected that the timer event will execute the function which alerts "Hello" string during the execution of the loop. However it happens only after the loop is finished.

Is it the language specific issue? How should I implement the callback function handling while being inside of some loop/execution?

maximus
  • 4,201
  • 15
  • 64
  • 117
  • There is no event handler in your example. What are you actually trying to achieve? – T.J. Crowder May 26 '13 at 08:39
  • what are you actually trying to achieve? – usoban May 26 '13 at 08:40
  • 1
    Javascript has only one execution thread, the code of your function will always execute before the callback of setTimeout, even if you set a timeout of 0 – bert May 26 '13 at 08:41
  • "How should I implement the callback function handling while being inside of some loop/execution?" Please elaborate what you actually need – sabithpocker May 26 '13 at 08:43

2 Answers2

10

You miss one key feature of the JavaScript internal structure: The event loop. All functions get stored there and wait until they get executed. Furthermore, JavaScript (in general - leaving out AJAX and workers) is single threaded, so at any time, just one function gets executed.

With respect to your script: The first function on the event queue is your ready() callback. It gets executed and while doing so places many other functions (the callbacks from the setTimeout() call) on the event queue. But in order to execute those, the first function has to be finished, meaning all the loop has to be done and the function has to return.

So basically this happens (the second row in each bullet point denotes the current event loop state):

  1. Just the ready callback is queued for execution.

    ready()-callback

  2. The setTimeout() callback gets placed on the event queue.

    ready()-callback | setTimeout()-callback

  3. All the looping is done.

    ready()-callback | setTimeout()-callback

  4. The ready() callback has finished and is removed from the queue.

    setTimeout()-callback

  5. Just now the setTimeout() callback is executed and you see your alert() message!

    setTimeout()-callback


So in order to get your alert() somewhere in between the loop execution, you either have to execute it after, e.g., the 2500th iteration:

$(document).ready(function(){
    var k = 0;
    for (var i = 0; i < 5000; ++i) {
        ++k;
        $('.inner').append('<p>Test</p>' + k.toString());
        if( i == 2500 ) {
          alert( 'Hello' );
        }
    }
});

Or put all those inserts in setTimeout() callbacks too (which require some kind of closure, if you want to access the outside k):

$(document).ready(function(){
    var k = 0;
    setTimeout(function(){alert("Hello")},500);
    for (var i = 0; i < 5000; ++i) {
        ++k;
        setTimeout( (function( k ) { 
          $('.inner').append('<p>Test</p>' + k.toString());
        })( k ), 0 );
    }
});
Sirko
  • 72,589
  • 19
  • 149
  • 183
1

Yes, its a language issue. A setTimeout in JavaScript executes the code after the number of milliseconds specified, in your case 500. It queues the script and goes on to execute the next line of code and therefore your loop is executed while the thread will wait for 500 ms to execute your alert.

If you want the for loop to run after 500 ms do this

setTimeout(function(){
    for (var i = 0; i < 5000; ++i) {
        ++k;
        $('.inner').append('<p>Test</p>' + k.toString());
    }
},500);
Arun
  • 3,036
  • 3
  • 35
  • 57