I have been reading this article http://ejohn.org/blog/how-javascript-timers-work/ and how setTimeout
and setInterval
and other async tasks such as button click confused me a little.
I know that JS is a single threaded, that means, AFAIK, all the callback functions (a.k.a. event handlers) will be queued and executed in order. However, look at the image below that I took from the article, linked above:
Each block represents some work, and - at around 10ms - the timer gets fired. I know that its callback function is put on the queue for later execution, but how come the event can get called while something is being executed already?
Is it because setTimeout()
starts using a separate thread to count the time internally and fire its completion event?
Please, note that I am not talking about its callback execution here; rather, I am trying to understand how setTimeout
can count the time and fires its completion. I know that its callback will be called not before its given time parameters, but maybe later but this is because its callback is queued to later time when the runtime finds some time to check whether there is anything to execute in the queue.
Similar to this question, how come browsers accepts new click to be registered while - let's say - a loop is working behind the scenes at the moment of user click?
If you say browsers maintain different threads for different things, then can we call JS in browsers single threaded?
JavaScript is single threaded, which means that two pieces of JavaScript will not execute at the same time (unless using a worker, but each worker is also single-threaded). But JavaScript isn't the only thing at play when it comes to the environment's API's. Functions like setTimeout
, setInterval
and addEventListener
are implemented natively (or, at-least, outside of the single-threaded JavaScript), and their callbacks are triggered by the environment, such as a browser. It is the environment that puts these callbacks onto the queue, to be executed by the single threaded JavaScript engine. This is how the browser is able to accept new click events to be fired, even though it is still executing some other JavaScript code. This is the reason JavaScript is considered event-driven.
There is no need to have other threads to explain this behavior. When a timer record is added into the queue, it simply sits there. If the event loop gets control again, it simply checks whether there is a scheduled task whose time is up or not.
There is also no need for an additional thread to keep the global time since this is already delivered by the OS or the execution environment.
Take for example this simple PhantomJS script:
function longRunningTask() {
for(var i = 0; i < 100000; i++) {
var s = "",
s2 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
for(var j = 0; j < 1000; j++) {
s += s2;
}
}
}
var start = new Date().getTime();
console.log("begin");
setTimeout(function(){
console.log("end timer 1s " + (new Date().getTime() - start));
}, 1000);
setTimeout(function(){
console.log("end timer 10s " + (new Date().getTime() - start));
}, 10000);
longRunningTask();
console.log("end longRunningTask " + (new Date().getTime() - start));
setTimeout(function(){
console.log("EXIT");
phantom.exit();
}, 11000);
Which produces the following output:
begin end longRunningTask 5025 end timer 1s 5029 end timer 10s 10001 EXIT
The one second timer only fires when the control is given back to the event loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With