JavaScript Asynchronous Life Cycle Simply Explained

JavaScript Asynchronous Life Cycle Simply Explained

JavaScript has a lot of power today. It drives all the front end applications on browsers, delivers back end applications (NodeJS) and more. JavaScript is not exceptional from other programming domains, means that as a JavaScript professional developer you have to know a few things about the internals of the language in order to create great applications. There are few misconceptions and lack of knowledge that some JS developers face along their career, and gathering this knowledge and breaking those misconceptions can of course help them to create even greater products. In this post we will bust the myth of “JavaScript is Asynchronous”.

JavaScript Is Not Asynchronous

The most common misconception among JS developers is that JS is asynchronous language. Actually I cannot think of a programming language that indeed is asynchronous, and what the hell does that mean “Asynchronous Language” anyways?

Asynchronous term in JavaScript is related to the way of JS deferring tasks to execute in a later stage of code run time. The way JavaScript runs it asynchronous calls are handled by the context in which JavaScript is running (browser, NodeJS, etc). For example the most simple asynchronous function setTimeout is not native JavaScript function, it is implemented differently in the browser and in nodeJS. Actually JavaScript is processing and executing it’s commands one line at a time, line by line, or in other words it is a “synchronous language” or in the real word terms: blocking single thread programming language. To examine this write a small program with a big while loop followed by a console.log, you can see that the console.log isn’t executed until the loop finished.

There are a few ways to deal with asynchronous tasks (such as reading and writing to database, dealing with OS I/O, etc). Callbacks, promises and async/await functions and more, are the way JavaScript enables you to execute asynchronous tasks and get back the responses. Those all are a syntactic way to deal with those problems, but what happens behind the scenes?

Behind The Scenes

The part that manages The execution logic called the V8 engine, you might have heard about it here and there in the context of chrome browser and NodeJS. V8 is the JavaScript engine that drives the chromium project (chrome browser is based on chromium). NodeJS is implemented on top of V8 also.


When we execute synchronously our code, line by line, yes, even your asynchronous functions, they are pushed into something called the stack. I won’t get too much into details here. In short, each function call creates a space in memory called frame that contains all information for it to be executed, for example the arguments, and this fame is pushed to the top of the stack. When the function returns, its frame is popped out of the stack. Using a stack is a very familiar way to deal with synchronous operations, because you can tell exactly when a function is running and when it is returned. Actually you might have used this stack when debugging your application. When you get an execution error on the browser for example, you can see the stack trace is printed out, this is easily done because of the stack data structure. And of course the mighty stack overflow error is thrown when the stack gets bloated with too many frames, in chrome browser the limit is 16000 frames.


The heap is a region in the memory where arbitrary data can be stored in 
unordered way. (The ECMAScript language specification doesn’t specify definition on memory layout, so what does it in real life is the interpreter). In other words, V8 (written in c++) handles memory allocation in a way that it allocates the memory in the heap and uses pointers to those variables in the stack which is much more ordered and fast. V8 engineers of course made a lot of optimizations to this abstract review I wrote, so for example atomic variables such as booleans are actually stored in the stack, and much more optimizations also done in this engine. The heap has also to do with the Garbage Collector but we will leave this to another post.


The queue is the core of this post. The queue is a place in memory which queues messages associated with the asynchronous tasks (callbacks) created by your program. If a callback is not created, no message is pushed into the queue, for example mouse move events without callbacks. The messages in the queue are processed in order (FIFO) as the stack gets empty (or other logic implemented by the interpreter), and what manages this execution is something called the Event Loop.

The event loop is (as the name suggests) an infinite while loop that queries the stack and the queue for tasks to do. When the stack gets empty it takes the next task from the queue and pushes it to the stack (as a frame) there it would be executed like a regular function. This is the reason asynchronous code is hard to debug, because those functions pushed to the stack are out of context when the time of execution comes, so for example the stack trace won’t help us too much (this is of course gets optimized with each version of JS released).


AJAX HTTP Requests Cancellation

AJAX HTTP Requests Cancellation

Sometimes when we call the server to perform some action as a response to an AJAX request, we want to discard this request because of particular reason. For example I had to perform a render action for a request with some parameters and send back as a response rendered template in HTML markup. This cancellation should help us dealing with unnecessary responses from server as well as avoiding redundant network traffic and unsynchronized UI when.


Alice fills a form on the client side, for example name and phone and gets back from the server the fancy decorated rendered html to the browser.


We obviously don’t want to create a request for each character filled in the form so we create some sort of a debounce function to help us reduce the HTTP requests. But we can do even more. Suppose that we have a debounce function of 2 seconds, and Alice filled her name in the name field, waited for 2 seconds that started to fill the phone field. Obviously a new request will be fired to the server while the older request is still live, but we don’t need the older one because it is now not synchronized with the UI. We need a way to cancel the old request and to treat only the latest request.

Naive Code And Example

here I created a little demo of the situation with the debounce function and a function to mock the AJAX task. Of course it is not the best code you will ever see and uses jQuery and blah blah but that clears the point. If you notice and sharp enough you can make a render request and while the request is being processed you can create another request for render.


Abort To The Rescue

The JavaScript xhr function (which I believe is still being used by most of the libraries/frameworks, for example vueResource and the before parameter where you would cancel the xhr request) comes with an option to abort it self. The only addition to the code above is single condition which can help your application reduce requests even more (with the debounce function)