DEV Community


Posted on


Asynchronous JavaScript: callbacks, promises, Async/await, Event loop - part 2

In the first part of this topic we could see that ​​even though javascript is a single-threaded language, the environment in which it is executed helps us to work in an asynchronous way.

Many elements are involved in the execution of our code and one of those elements is the Web APIs. Operations we can do with the web APIs are: Fetch data, Set local storage, DOM manipulation, etc… These actions are taken apart from the main thread while they are completed. Now the question is, How does our program know when operations have ended? What are we going to do once these operations are finished?

It’s here where javascript brought to the table different mechanisms in order to control and manage these asynchronous actions. Let's take a look.

Callbacks represent: What do you want to do once your asynchronous operation is over?

Most asynchronous actions take as an argument another function (callbacks), and once the asynchronous task is finished, the callback function is called.

To see a callback in action lets take as an example setTimeOut, which is an asynchronous function that takes a callback and the time at which it should be executed.

Image description

  • ‘Hello’ is printed on the console
  • Secondly, the setTimeOut function is taken to another thread, and allows the script to continue running. (setTimeOut is a Web API, so it’s placed inside its respective container)
  • The last line of code is executed, ‘End’ is printed on the console
  • Event loop, check that the call stack is now empty and the callback queue has one callback in line.
  • Then move the console.log function to the call stack and now we can see the word ‘world’ printed on the console.

Important to realize that even if we configure our setTimeOut to run in 0 seconds. It’s not going to be executed immediately. The result is going to be the same as before due to the setTimeOut being run in another thread.

The problem comes when you need the result of one function to call the following function. Then you start to nest as many callbacks as you need.

Image description

In essence, we are doing more complicated things, detracting from legibility, making the code difficult to maintain. This structure is also known as the Pyramid of Doom, or Callback hell.

Promises: introduced with ECMAScript 6, and brought to the language a more concise way of working with asynchronous functions

According to Eloquent Javascript: “A promise is an asynchronous action that may complete at some point and produce a value. It is able to notify anyone who is interested when its value is available”

One of the most common uses of promises in web development is to control the flow of requests (Ajax) to web servers. Let's take a look at the following snippet.

Image description

We have the Fetch method, a web API that returns a promise, and instead of passing async functions we attach them with another method called then(). The result is a more legible and maintainable code, fixing the clutter of nested callbacks and also, making error handling simpler.

One last thing that is important to mention is that with the introduction of Promises, a second high-priority queue was incorporated into the javascript runtime environment. This new queue is called the ​​microtask queue. So when a new promise event occurs, this priority queue will be serviced first. Thus, we ensure that the callbacks of the promises will be executed in the future, and as soon as possible.

If you want to dig deeper on how to actually create a Promise and how to handle errors click on here.

ECMAScript 7 and the arrival of async/await

As mentioned earlier, with the advent of promises we are able to avoid nesting callbacks and structure our code a little better. Yet javascript found a way to give us another methodology where we can still handle asynchronous tasks but drop the chaining model of then() to use one in which we work in a more traditional way.

Image description

  • First of all, we have the keyword async that it’s placed before the function we want to define as asynchronous
  • Inside the function, we now can proceed to use the word await, and as the name implies, causes the browser to pause the execution of JavaScript code until the promise implied is resolved.
  • Optionally, in case you want to check for errors or rejected promises, you can always use try/catch blocks.

Note that, in the end, async await is a syntactic sugar for promises. The code looks sequential, in a synchronous way but it’s still a promise-based asynchronous code. It is also mentioned that this method enables some interesting optimizations of Memory and performance too in JS Engine.

Top comments (1)

karimrostov profile image

Thanks, Cin.

So, I am a senior full stack developer and I think we can collaborate each other in many side of development.

Yours Truly.

Visualizing Promises and Async/Await 🤓

async await

☝️ Check out this all-time classic DEV post on visualizing Promises and Async/Await 🤓