Javascript event handling inside a loop

I made the following program for 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 the timer event to execute a function that warns the string "Hello" during the execution of the loop. However, this only happens after the cycle ends.

Is this a language problem? How should I implement callback function processing while inside some loop / execution?

+2
javascript
May 26 '13 at 8:36
source share
2 answers

You miss one key function of the internal JavaScript structure: the event loop. All functions are stored there and wait until they are completed. In addition, JavaScript (generally, abandoning AJAX and workers) is single-threaded, so only one function is executed at any time.

As for your script: the first function in the event queue is your ready() callback. It is executed, and many other functions (callbacks from the setTimeout() call setTimeout() placed in the event queue. But for their execution, the first function must be completed, which means that all cycles must be completed, and the function must return.

So, basically this happens (the second line at each marker point indicates the current state of the event loop):

  • Only the ready callback is queued for execution.

    ready () - callback

  • The setTimeout() callback is placed in the event queue.

    ready () - callback | SetTimeout () - callback

  • The whole cycle is running.

    ready () - callback | SetTimeout () - callback

  • ready() callback completed and removed from the queue.

    SetTimeout () - callback

  • Now the setTimeout() callback is executed and you see the alert() message!

    SetTimeout () - callback




So, to get alert() somewhere between the execution of the loop, you either need to execute it after, for example, 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 of these inserts in setTimeout() callbacks too (which require some kind of closure if you want to access external 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 ); } }); 
+10
May 26 '13 at 8:42
source share

Yes, this is a language problem. SetTimeout in JavaScript executes the code after the specified number of milliseconds, in your case 500. It queues the script and continues to execute the next line of code, and therefore your loop is executed while the thread waits 500 ms before you execute your warning.

If you want the for loop to work after 500 ms, do it

 setTimeout(function(){ for (var i = 0; i < 5000; ++i) { ++k; $('.inner').append('<p>Test</p>' + k.toString()); } },500); 
+1
May 26 '13 at 8:45
source share



All Articles