DEV Community

Brian Barbour
Brian Barbour

Posted on

If Javascript Is Single Threaded, How Is It Asynchronous?

Javascript is a single threaded language. This means it has one call stack and one memory heap. As expected, it executes code in order and must finish executing a piece code before moving onto the next. It's synchronous, but at times that can be harmful. For example, if a function takes awhile to execute or has to wait on something, it freezes everything up in the meanwhile.

A good example of this happening is the window alert function. alert("Hello World")

You can't interact with the webpage at all until you hit OK and dismiss the alert. You're stuck.

So how do we get asynchronous code with Javascript then?

Well, we can thank the Javascript engine (V8, Spidermonkey, JavaScriptCore, etc...) for that, which has Web API that handle these tasks in the background. The call stack recognizes functions of the Web API and hands them off to be handled by the browser. Once those tasks are finished by the browser, they return and are pushed onto the stack as a callback.

Open your console and type window then press enter. You'll see most everything the Web API has to offer. This includes things like ajax calls, event listeners, the fetch API, and setTimeout. Javascript uses low level programming languages like C++ to perform these behind the scenes.

Let's look at a simple example, run this code your console:

console.log("first")
setTimeout(() => {
    console.log("second")
}, 1000)
console.log("third")
Enter fullscreen mode Exit fullscreen mode

What did we get back?

first
third
undefined
second
Enter fullscreen mode Exit fullscreen mode

Feels odd, right? Well, let's break this down line by line:

console.log("first") is on the stack first, so it gets printed. Next, the engine notices setTimeout, which isn't handled by Javascript and pushes it off to the WebAPI to be done asynchronously. The call stack moves on without caring about the code handed off to the Web APIs and console.log("three") is printed.

Next, the Javascript engine's event loop kicks in, like a little kid asking "Are we there yet?" on a road trip. It starts firing, waiting for events to be pushed into it. Since the setTimeout isn't finished, it returns undefined, as the default, well because it hasn't been given the value yet. Once the callback finally does hits we get console.log("second") printed.

There's a really good site that slows this all down and shows this happening.

http://latentflip.com/loupe

I suggest playing around in this sandbox to help solidify your understanding. It helped me get a feel for how asynchronous code can work with Javascript being single threaded.

Top comments (47)

Collapse
 
karataev profile image
Eugene Karataev

I like asynchronous nature of javascript because it helps me to sort arrays easily. No more bubble, selection, merge or quick sort algorithms. Timeout sort for the win!

let arr = [10, 100, 500, 20, 35];

arr.forEach(item => {
  setTimeout(() => console.log(item), item);
})
// 10 20 35 100 500
Enter fullscreen mode Exit fullscreen mode

🤣🤣🤣

Collapse
 
bradley profile image
Bradley Griffith • Edited

did a flex-box version: jsfiddle.net/bradleygriffith/2dsag...

<div class="sorted-list" id="my-list"></div>

Enter fullscreen mode Exit fullscreen mode
.sorted-list {
  align-items: flex-start;
  display: flex;
  margin: 0 -5px;
}

.sorted-list-item {
  margin: 0 5px;
}
Enter fullscreen mode Exit fullscreen mode
const listEl = document.getElementById("my-list");
const arr = [10, 100, 500, 20, 35];

arr.forEach(n => {
  const itemEl = document.createElement("div");

  itemEl.className = "sorted-list-item";
  itemEl.innerHTML = n;
  itemEl.style.order = n;

  listEl.appendChild(itemEl);
});

Enter fullscreen mode Exit fullscreen mode
Collapse
 
awcode0x profile image
AWCode0X

It's amazing
good work

Collapse
 
karataev profile image
Eugene Karataev

Ahaha, awesome! 😂

Collapse
 
antonocheret profile image
Anton

half a second sort for 5 items, very quickly

Collapse
 
ignore_you profile image
Alex

Unfortunatelly, this cute sorting algorithm doesn't work on values that < 1.

Collapse
 
karataev profile image
Eugene Karataev

It also poorly works with floats (ex. [1.5, 1.4, 1.3, 1.2, 1.1]) and big numbers 😄

Thread Thread
 
saurabh_bakolia_a5f9fc09d profile image
SAURABH BAKOLIA

Try with this example: [10, -100, 500, -20, 35];

Collapse
 
bbarbour profile image
Brian Barbour

In the course I'm doing we had to use setTimeout as a way to avoid stack overflow. I don't think I'd ever do it in a real app, but it was an interesting trick.

Collapse
 
timepp profile image
timepp

This is mostly equivlant with the following code

let arr = [10, 100, 500, 20, 35];
let sorted = 0
for (let i = 0; sorted < arr.length; i++) {
    for (const v of arr) {
        if (v === i) { 
            console.log(v);
            sorted++;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
fc250152 profile image
Nando

I think you are a bit crazy, bro ;)

Collapse
 
sirius93 profile image
Nandan Kumar

Hey Eugene,
Would you please help me understand how does this happen. Any link or reference would be very helpful.

TIA :)

Collapse
 
karataev profile image
Eugene Karataev

Well, it's a joke and shouldn't be used anywhere in production code.

We iterate on every element (N) in array of numbers and ask a JS engine to log this number in the console after N milliseconds from now. So, these numbers will be logged in a sorted way, because time in our universe flows in one direction 😁

Thread Thread
 
sirius93 profile image
Nandan Kumar • Edited

Yes, indeed it's a joke and should not be used anywhere in production. But it's nice to know how things work, It took me some time to figure out but it was worth it.
Thanks 😁

Collapse
 
jamesqquick profile image
James Q Quick

This is amazing lol

Collapse
 
hamza_pasking_akhtar profile image
Hamza Pasking Akhtar

Lol I just saw a content creator talking about this that she interviewed someone that wrote a code this way.

I mean it works, it's creative. 😂

Collapse
 
aqeel613 profile image
Syed Aqeel

This is called timeout sort I think :D

Collapse
 
abhiipure1289 profile image
Abhishek Bhardwaj

It has limitation that if any item of array contained number in billion or millions it will keep in waiting unless the time finish.

Collapse
 
prabhjeet6 profile image
Prabhjeet Singh

how does it sort with timeout? should it not pick items with index

Collapse
 
ryanmattos profile image
Ryan Mattos

genius

Collapse
 
prahladyeri profile image
Prahlad Yeri • Edited

Not all apps are benefited by javascript's async nature though, only those which are I/O centric. Apps which are more CPU centric like those involving statistical computations or heavy algorithms tend to perform better with non-async languages like java and python.

But when it comes to web development, about 90% of them are pure Database/CRUD or I/O centric apps, hence javascript could be useful in most cases.

Collapse
 
totiiimon profile image
Totiimon

Did you mean to say that some apps are not benefited by the fact that Javascript is single threaded instead? Having async functionality is not a bad thing since languages like Rust or Python have async funtionalities, but what they also have, is multi-threaded capabilities.

Collapse
 
prahladyeri profile image
Prahlad Yeri

Exactly, multi-threading or parallel computing is the key when it comes to a lot of tasks. In fact, to take the full advantage of the 4 cores of your CPU, multi-threading is a must. Async will never be able to do that however efficient it may otherwise be.

It all comes down to what your app needs to do. I/O bound operations are where async shines and you should make full use of that if your app is majorly I/O bound.

Collapse
 
dance2die profile image
Sung M. Kim

I've tried with setTimeout delay of 0, which I expected to run before third.

console.log("first")
setTimeout(() => {
    console.log("second")
}, 0)
console.log("third")
first
third
undefined
second
Enter fullscreen mode Exit fullscreen mode

but I was surprised to see that second was returned last.

Collapse
 
owl profile image
Oscar • Edited

The function in your timeout gets queued as a task. The script runs and once it is done (console.log('third')), the engine can handle the task queue and will execute the timeout callback. So, even though the timeout is zero, the function will not get called immediately.

There is a lot more to the topic and Jake Archibald wrote an amazing article about how this works. I highly recommend reading it:

jakearchibald.com/2015/tasks-micro...

Collapse
 
dance2die profile image
Sung M. Kim

Thank you, Oscar 🤜

Collapse
 
elijahtrillionz profile image
Elijah Trillionz

It's an interesting thing about it.
No matter the delay it will always come after the call stack is empty.
Try using this website loupe to see more of it.

Collapse
 
realtimecarsten profile image
realtimecarsten

In most operating systems, the wait or sleep functions are lower bounds - wait(n) will wait for at least n time-units, but once the time is up, you will never know when your tasked is scheduled next - sometimes that can be really long.

Collapse
 
yogiwisesa profile image
Yogi Wisesa

Hey Brian, coming from the future here. I'm a little bit confused by this statement "Well, we can thank the Javascript engine (V8, Spidermonkey, JavaScriptCore, etc...) for that, which has Web API that handle these tasks in the background. ", if the task is handled in the background so it's mean if the javascript isn't single thread right? since the code is executed in the same time. thank you!

Collapse
 
freelancer2020 profile image
Mostafa

Mastering this topic I considered as a fundamental of being a JavaScript developer, knowing more about JavaScript engine (compiler) , the browser mechanisms and critical rendering path ( CRP ) is very important thing! I advise the developers who want to be a rock in web development field, please go through this topics and learn them carefully and on top of that make a deep understanding of network layer like http requests, responses, cache, cookies, storage, sessions. And related stuff to a browser network.

Collapse
 
aleksandar15 profile image
Aleksandar15

I think you are wrong at this part ...we can thank the Javascript engine (V8, Spidermonkey, JavaScriptCore, etc...) for that, which has Web API....

We don't thank JS Engine for that, because Web API is not part of the JS Engine but the JS runtime environment provided by the Browser, also provided by the browser is the JS Engine itself (V8 for Chrome) and Callback Queue and the Event Loop.
The JS (V8) Engine is made up of Memory Heap & Call Stack.

Furthermore, the purpose of the JS engine is to parse/translate source code that we developers write into machine code that allows a computer to perform specific tasks on its hardware level.

Collapse
 
marouaneat95 profile image
marouaneat95

Great article but there's something I can't understand
Isn't the "console" considered a Browser API an not a built-in Javascript object? why doesn't the JavaScript handles the console.log() function to the console API in the same manner it does with well known async functions (setTimeout, setInterval...etc etc) and moves to the next line of code ? Same thing for DOM manipulation which depends on the DOM API?

Collapse
 
flrnd profile image
Florian Rand

Wow Brian, the video talk from Philip Roberts it's gold! thanks for sharing this!

Collapse
 
britain profile image
Britain Green

Great, Brian!

Collapse
 
vagoel profile image
Varun

Thanks Brian for sharing the video link.Its really amazing and easy to understand the complexity behind JavaScript's call stack/event loop/callback queue.