DEV Community

Cover image for The Single-Threaded Nature of JavaScript/Typescript: Async Programming
Egi Mata
Egi Mata

Posted on

The Single-Threaded Nature of JavaScript/Typescript: Async Programming

We are going to explore the async nature as a single threaded language.

In JavaScript & TypeScript, the single-threaded nature means that only one task can be executed at a given time.

On the other hand async programming refers to the ability of the language to perform tasks asynchronously, allowing the main thread of execution to continue running while waiting for other tasks to complete. This is achieved through the use of callbacks, events, promises and async/await.

Before I begin explaining these in coding terms, I would like to talk about a very interesting reference of how async tasks of a single-threaded language is very similar to our brain when we try to do multitasking.

In this section I will summarize a long text / chapter written from Kyle Simpson in his book “You Dont Know Javascript” about the connection of Sequential Brain with asynchronization. If you are interested only on the coding part of how it works, you can skip this part.

I’m pretty sure most of you have heard someone say (even made the claim yourself), “I’m a multitasker.”
But are we multitaskers? Can we really do two conscious, intentional actions at once and think/reason about both of them at exactly the same moment? Does our highest level of brain functionality have parallel multithreading going on?

The answer may surprise you which is: probably not.

That’s just not really how our brains appear to be set up. We’re much more single taskers than many of us would like to admit. We can really only think about one thing at any given instant.

I’m not talking about all our involuntary, subconscious, automatic brain functions, such as heart beating, breathing, and eyelid blinking. Those are all vital tasks to our sustained life, but we don’t intentionally allocate any brain power to them."

According to Simpson, humans are not capable of truly multitasking in the same way that a computer can. While it is true that the human brain can process multiple tasks simultaneously, it is not able to give equal attention to all tasks at once. Instead, we rapidly switch our attention between tasks, much like a single threaded program can only execute one task at a time.

Thankfully, while we obsess about checking social network feeds for the 15th time in three minutes, our brain carries on in the background (threads!) with all those important tasks.

I’m not talking about all our involuntary, subconscious, automatic brain functions, such as heart beating, breathing, and eyelid blinking. Those are all vital tasks to our sustained life, but we don’t intentionally allocate any brain power to them.

There’s a big, observable difference between how we plan various tasks, and how our brains actually operate those tasks.
Even though at an operational level our brains are async evented, we seem to plan out tasks in a sequential, synchronous way. “I need to go to the store, then buy some milk, then drop off my dry cleaning.

Can you actually imagine having a line of thinking that plans out your to-do errands like this:

"I need to go to the store (1), but on the way I’m sure I’ll get a phone call (2), so ‘Hi, Mom’, and while she starts talkin, I’ll be looking up the store address (3) on GPS, but that’ll take a second to load, so I’ll turn down the radio (4) so I can hear Mom better …
then I’ll realize I forgot to put on a jacket (5) and it’s cold outside, but no matter, keep driving and talking to Mom …
and then the seatbelt ding reminds me to buckle up (6), so ‘Yes, Mom, I am wearing my seatbelt, I always do!’. Ah, finally:
the GPS got the directions, now…"

As ridiculous as that sounds as a formulation for how we plan our day out and think about what to do and in what order, nonetheless it’s exactly how our brains operate at a functional level. But remember, that’s not multitasking, it’s just fast context switching.

With this in mind, let’s take a closer look at how async programming works in JavaScript.

Now to coding:

There are several ways to perform async programming in JavaScript/Typescript, as I mentioned in the beginning of this article, including using: Callbacks, Events, Promises, Async/Await.

A callback is a function that is passed as an argument to another function and is executed after the outer function has completed. For example:

function greet(name, callback) {
  console.log(`Hello, ${name}!`);
  callback();
}

function sayGoodbye() {
  console.log("Goodbye!");
}

greet("John", sayGoodbye);
// Output: "Hello, John!"
// Output: "Goodbye!"
Enter fullscreen mode Exit fullscreen mode

The greet function takes a name and a callback function as arguments. The greet function logs a message with the provided name and then calls the callback function. Then the sayGoodbyefunction is passed as a callback to the greet function and is executed after the greet function has finished.

An event is a signal that something has happened, and a listener is a function that is executed in response to that event. For example:

const button = document.querySelector("button");

button.addEventListener("click", () => {
  console.log("Button was clicked!");
});
Enter fullscreen mode Exit fullscreen mode

In the example above, a listener function is added to the click event of a button element. When the button is clicked, the listener function is executed and it will log into the console “Button was clicked!”.

A promise represents the result of an async operation, and can be either resolved (successful) or rejected (failed), just like real life promises; when you make a promise you either keep (resolve) it or don’t (reject).
Promises can be used to simplify the process of chaining async operations together. For example:

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Completed Async Task");
  }, 1000);
});

promise.then((result) => {
  console.log(result);
});
// Output: "Async task completed" (after 1 second)
Enter fullscreen mode Exit fullscreen mode

In this example, a promise is created that will resolve with the message “Completed Async Task” after a 1-second delay. The then method of the promise is used to specify a callback that will be executed when the promise is resolved.

Async/await: a feature of JavaScript that allows the use of async/await syntax to make async code look and behave like synchronized code. Async/await is built on top of promises and makes it easier to work with async code.

async function greet(name) {
  return `Hello, ${name}!`;
}

async function main() {
  const greeting = await greet("John");
  console.log(greeting);
}

main();
// Output: "Hello, John!"
Enter fullscreen mode Exit fullscreen mode

The greet function is marked as async and returns a promise. The main function is also marked as async and uses the await keyword to wait for the greet function to resolve before logging the result.


In other words, async programming in JavaScript and TypeScript can provide a similar experience to multitasking by allowing the main thread of execution to continue running while waiting for other tasks to complete.

Overall, async programming allows for the execution of multiple tasks while maintaining the single-threaded nature of the language. It allows for a more responsive and efficient program by allowing the main thread to continue running while waiting for other tasks to complete.


If you like this content don’t hesitate to follow. There are many more projects at hand on which I am planning to write about in the near future. Until then,

Thank you for reading!

Top comments (0)