55

I have a question about the single threaded nature of Javascript.

console.log("1");
setTimeout(function(){console.log("2");},3000);
console.log("3");
setTimeout(function(){console.log("4");},1000);

The result of this code is 1 3 4 2. As you see, 4 comes after 2 which makes me wonder that in a single threaded environment shouldn't 2 have come after 4? If not, then how come JS knows the second setTimeout should finish before the first one? Shouldn't there be two threads which work concurrently to complete the two setTimeouts in order to notify EventLoop?

Tarik
  • 73,061
  • 78
  • 222
  • 327

6 Answers6

38

JavaScript (in browsers) doesn't run concurrently2.

At most one of the setTimeout callbacks can execute at a time - as there is one JavaScript execution context or "thread".

However, the "next scheduled timeout" to run is always run .. next. The "4" runs before the "2" callback because it was scheduled to run sooner. The timeouts were effectively scheduled from the same time (none of the operations were blocking), but "2" had a much longer interval.

The underlying implementation may use threads1 - but JavaScript in the same global context doesn't run concurrently and guarantees consistent and atomic behavior between all callbacks.


1 Or it may not; this can be handled without any threads in a select/poll implementation.

2 In the same context: i.e. Tab/Window, WebWorker, host Browser Control. For example, while WebWorkers are run concurrently they do so in different contexts and follow the same asynchronous model (eg. as used by timers).

user2864740
  • 54,112
  • 10
  • 112
  • 187
22

Javascript uses something called Eventloop for Asynchronous calls. The setTimeout is pushed to EventLoop since it is a callback. and the main thread continues to execute. Once the main completes, Then the EventLoop pushes the data to the main stack. Ex:

console.log("1");
setTimeout(function(){console.log("2");},0);
console.log("3");
setTimeout(function(){console.log("4");},1000);

When the timeout is 0, then the output of the code will be,

1 3 2 4

Since it first executes the calls of the Main and then brings back data from Eventloop Concurrency model and Event Loop

Siddaram H
  • 884
  • 7
  • 14
11

Javascript executes each line in sequence.

So you told js:

  • write 1: js writes 1
  • wait 3 seconds and then write 2: ok I'll wait 3 seconds...now what?
  • write 3: ok I'll write 3, by the way, the 3 seconds is not up.
  • wait 1 second and then write 4: ok I'll wait 1 second...

then js waits .99999 seconds ... and writes 4

then waits some more and writes 2

Brian McGinity
  • 5,329
  • 5
  • 33
  • 46
  • 4
    "by the way, the 3 seconds is not up" is misleading. There is no possibility that JavaScript would execute something there, even if a timer's time has come, precisely because JS is single-threaded. JS thread can either be in-code or out-of-code; while it is in-code, it cannot execute anything else. Any timeouts only happen when your code relinquishes command of the JS engine (by exiting from the outermost function). – Amadan Feb 12 '14 at 04:52
  • This is a very unsatisfying explanation. What about `setTimeout` which allows for multiple, overlapping timeouts to be running at the same time. What about the fact that event callbacks that depend on external sources, such as a result on `XMLHttpRequest`, have to be able to start at any time, but still run on that same thread? No offence, but this answer feels way too general. – Shien Sep 30 '16 at 18:42
  • @Shien setTimeout() is still running single threaded and hence the reason they are not guaranteed to fire at the exact millisecond. To help understand see: http://ejohn.org/blog/how-javascript-timers-work/ – Brian McGinity Oct 06 '16 at 19:39
6

the second parameter of setTimeout takes in the minimum time after which the callback function (first argument) is to be pushed onto the event loop, which is nothing but a queue for callback functions. This queue is consumed to actually start execution.

Once first setTimeout is encountered, function is pushed onto someplace outside and is told to wait for 3 seconds before re-entering in single threaded world. Same happens for second timeout function however it has to wait only 1 sec. The entry point to this single threaded world is the callback queue. JS Engine continues normal execution as if settimeout execution is done with. Now once 1 sec expires, the function of second timeout is pushed onto the queue and waiting to be executed. If the call stack is clear at that point of time then the function goes for processing(assuming it was the first member of the queue) and "4" is printed. Now if 3 sec has not passed in this time, the function of first timeout is still waiting someplace outside. Once 3 seconds pass, the callback function enters the queue and since the call stack is clear, it executes and "2" is printed.

Now browser has access to multiple threads from the OS (though providing only a single threaded environment for JS execution). These setTimeouts are processed by another thread behind the scene.

There is a video by Philips Robert that beautifully explains the concepts of queue and event loop that lead to 'asynchronousness' of single threaded javascript.

https://www.youtube.com/watch?v=8aGhZQkoFbQ

Nikhil Sahu
  • 2,032
  • 2
  • 29
  • 41
0

Here are the steps:

  1. Adding console.log(1) to the JS call stack. time(~0)

  2. Executing it. (prints 1 in console) - time(~0)

  3. Adding setTimeout(function(){console.log("2");},3000); to the call stack. - time(~0)

  4. Move it to the event loop and start the timer. - time(3 sec)

As setTimeout is an asynchronous function it will move to the event loop.

  1. Adding console.log(3) to the JS call stack. time(~0)

  2. Executing it. (prints 3 in console) time(~0)

  3. Adding setTimeout(function(){console.log("4");},1000); to the call stack. time(~0)

  4. Move it to the event loop and start the timer. - time(1 sec)

  5. The 1-second timer is finished so it will move back to the call stack and get executed.

  6. Call Stack executes it. (prints 4 in console) - time(~0)

  7. The 3-second timer is finished so it will move back to the call stack and get executed.

  8. Call Stack executes it. (prints 2 in console) - time(~0)

Now what we are calling synchronous is JS call stack which can execute only one thing at a time.

I could have made it a 20 steps process but for ease of understanding 12 are enough.

Aisha Hale
  • 33
  • 3
0

Definition - Multithreading: Multithreading is a type of execution model that allows multiple threads to exist within the context of a process such that they execute independently but share their process resources. In that sense JavaScript is totally multithreaded thing:

   let Ar;
    Ar = []

    function multiapp(ar,w,n) {
        ar.clear;
        for (let i = 0; i < n; i++)
            setTimeout(function(){ar.push(w)},i);
    }

    +function fn() {
        //Thread 1
        setTimeout(() => multiapp(Ar,1,10),100)
        //Thread 2
        setTimeout(() => multiapp(Ar,2,10),100)
    }()

    setTimeout(function(){console.log('Ar(1) = ', Ar.filter((i) => i == 1).length,'Ar(2) = ', Ar.filter((i) => i == 2).length,' Ar = ',Ar)},2000);
//Ar(1) =  10 Ar(2) =  10  Ar =  [ 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 ]`

Apparently thread 1 starts and executes its own stack, independently of thread 2. Two threads share access to the same context object instance Ar and modify it in unknown fashion. Behaves exactly as Java with atomic primitives.

brixdan
  • 79
  • 2