20

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:

enter image description here

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?

Alexander O'Mara
  • 58,688
  • 18
  • 163
  • 171
Tarik
  • 79,711
  • 83
  • 236
  • 349
  • Also, check out the answers to this question: http://stackoverflow.com/questions/1663125/is-javascript-multithreaded Your question adds an interesting element to the conversation. I don't know if it is a duplicate though as the question, itself, is substantially different – Thomas Feb 21 '15 at 20:32

3 Answers3

34

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.

Alexander O'Mara
  • 58,688
  • 18
  • 163
  • 171
  • So, on a "I have no idea what I am doing level" (because I don't), the browser is keeping track of some other environmental "stuff"? Can you elaborate on "natively executed" or point me in the right direction of some good reads? Very curious about this stuff, I am. – Thomas Feb 21 '15 at 20:38
  • 2
    @Thomas Unfortunately I don't have any links handy, but by "implemented natively", I mean these API's are implemented by the host environment, and are not implemented or executed in the single-threaded JavaScript, just the callback is. – Alexander O'Mara Feb 21 '15 at 20:44
  • 2
    the browser isn't necessarily multithreaded, either; you can very easily implement the image shown in the question with a pretty standard event loop, no threads required. – Eevee Feb 21 '15 at 20:45
  • This isn't quite correct. Multiple pieces of code can and do execute at the same time, but they have to be on separate web workers. (threads!) Web workers, however, must communicate with each other and with the main thread in a single-threaded way. – Agamemnus Feb 21 '15 at 20:55
  • @Agamemnus Eh, technicalities. I've added a note on this. – Alexander O'Mara Feb 21 '15 at 20:58
  • So, can you say that Event Loop is maintained and executed by the host environment? – Tarik Feb 22 '15 at 13:04
  • Great freaking answer! Very simple to understand and accurate – Gaspa79 Jan 24 '18 at 14:33
  • So does this mean the timer in setTimeout is in the environment and not managed by the execution thread?. Also when a custom callback of some API call move to the event loop, a mechanism like polling happens in the environment? – melkorCba Oct 23 '20 at 18:21
4

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.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
2

At present (Ecmascript 6), you never have to worry about the state changing midway inside a function.

Many things do act in the background however, and they change their own isolated environment which is later potentially sent to the main environment as chunks of data. The XMLHttpRequest callback queue, timers, and web workers all do this. They all potentially run at the same time (in multiple CPUs), but they all communicate with the main environment in a sequential way.

Agamemnus
  • 1,395
  • 4
  • 17
  • 41