Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript event handling while inside of loop

Tags:

javascript

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?

like image 523
maximus Avatar asked Aug 24 '26 10:08

maximus


1 Answers

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 );
    }
});
like image 95
Sirko Avatar answered Aug 27 '26 00:08

Sirko