Reputation: 4302
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?
Upvotes: 3
Views: 1216
Reputation: 74076
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):
Just the ready
callback is queued for execution.
ready()-callback
The setTimeout()
callback gets placed on the event queue.
ready()-callback | setTimeout()-callback
All the looping is done.
ready()-callback | setTimeout()-callback
The ready()
callback has finished and is removed from the queue.
setTimeout()-callback
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 );
}
});
Upvotes: 10
Reputation: 3077
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);
Upvotes: 1