JavaScript is single-threaded. This is to mean, it has one call stack (for performing operations) and one memory heap (for storing the variables). As a result, JavaScript code is executed in a synchronous manner. That is, from top to bottom, one line at a time, and must finish executing a single piece of code before moving onto the next.
How then are asynchronous operations possible in JavaScript? And why is it necessary to have asynchronous operations?
Now, synchronous execution is beautiful, but in cases where a piece of code takes too long to be executed, or has to wait on something (for example during network calls or when using timers), synchronous execution results in loss of time and resources as it freezes everything up, waiting for that specific execution to be complete before moving onto the next piece of code to be executed. This then brings in the necessity of asynchronous execution of code.
Asynchronous execution means; execution of a task is initiated now, but finished later on.
This is achieved through JS Runtime Environment which provides additional features to the script such as making API calls, setting timers, catching mouse/keyboard events.
To illustrate how an asynchronous operation is carried out. Let's take a look at what happens when a Web API call is made:
- API call.
- The API call function goes onto the call stack.
- Is it asynchronous? Can it be handled by JS Runtime Environment?
- If YES, the call stack passes on the task to the JS Runtime Web APIs and proceeds to the next function on the call stack, in a Last In First Out (LIFO) manner.
- The Web API stores the callback function for the task, and performs the task (that is making the API call).
- Once the task is finished (that is the API call has been made), the callback for that particular task is sent to the callback queue.
- The Event Loop continuously monitors the call stack. Once the call stack is empty, the callback function is pushed onto the call stack, in a First In First Out (FIFO) manner.
- The callback function is executed, and thus the asynchronous operation is successfully performed and finished.
A summary of the above steps is as in the illustration below:
In conclusion, JavaScript has the ability to perform tasks both synchronously and asynchronously despite being single-threaded. Asynchronous operations come in handy, saving time and resources for tasks that take too much time to be executed or depend on something else that takes time.
Any thoughts and comments, would love to hear those!