Asynchronous JavaScript - How I understand it.
Tags: javascript, webdev, node
Published: 2020-06-10 22:39:01

JavaScript is a single threaded language, which means that one command runs at time. It is also synchronously executed, making each command run in the order the code appears. 

So imagine we have a task that in our application which accesses a server to get data, and this process takes a long time. What if we have code that we need to run that displays the data response from the server? This poses a challenge, we want to wait for data from the server so that it is there to be displayed, but no code can be run in the meantime.

Enter **Asynchronous JavaScript**, the feature that makes dynamic web apps possible. We know that the JavaScript engine has three main parts - _The thread of execution_, _Memory (Heap)_ and the _Call stack_. However, these aren’t enough as JavaScript needs other external pieces from the Browser like the _Console_, _Timer_, _Sockets_, _Network requests_ and the _HTML DOM_ to function the way we want it to. 

JavaScript lets us interact with these tools by providing us with a bunch of functions (Web APIs) like **FETCH** for Network Requests, **Document** for the HTML DOM, **setTimeout** for the Timer and **Console** for the Console.

The **FETCH API** is two pronged, ergo it not only initiates the task in the web browser to make a network request to the address passed into it. It also has a consequence in JavaScript which returns a placeholder object called a Promise.


##What is a promise?
 
A promise in JavaScript is very much like a promise in real life. For example, if you make a promise in real life to visit a friend, this promise has two possible results. It is either fulfilled and resolved, or failed and rejected. What this means is that if you go visit your friend, the promise has been fulfilled and resolved, but if you don’t, the promise will be rejected because you were unable to fulfil the promise.

In JavaScript, a promise is an object with three properties, _Values_, _onFulfilled_ and _onRejected_. This promise will produce a value in future: a resolved value, or a reason why it is not resolved (e.g., if a network error occurs).

We’ll see an example of how promises work using some code, but before we start we need to define some concepts that will help us along the way.


**Event Loop** - This is responsible for executing the code, collecting and processing events, and executing queued sub-tasks.

**Callback queue** - This is where your asynchronous code gets pushed to wait for the event loop to push it into the call stack for execution.
 
**Micro-task queue** - Like the callback queue, but has a higher priority which means the event loop checks to see that the micro task queue is empty before moving on to the callback queue.

**Execution context** - This basically holds all the information about the environment within which the current code is being executed.


```javascript
const display = (response) => {console.log(response)}
const sayHi = () => {console.log(`say Hi`)}
const runFor300ms = () => { 
   // code that will run for 300ms
}
setTimeout(sayHi, 0)
const futureDisplay = fetch(`https://someserver.com/data/alex/1`)
futureDisplay.then(display)
runFor300ms()
console.log(`I am first`) 
```


Going through the code snippet above synchronously like the JavaScript engine would:

```javascript
const display = (response) => {console.log(response)}
```
First, declare and store the function _display_ in global memory.
```javascript
const sayHi = () => {console.log(`say Hi`)}
```
We declare and store the function _sayHi_ in global memory.
```javascript
const runFor300ms = () => { 
   // code that will run for 300ms
}
```
On line three, we also declare and store the function _runFor300ms_ in global memory.
```javascript
setTimeout(sayHi, 0)
```
The _setTimeout( )_ method is called, and it triggers the timer in the web browser to execute the function _sayHi_ at 0ms, which is when the timer is set to expire. At exactly 0ms, which is immediately, the _sayHi_ function is pushed into the _callback queue_ where it waits for the call stack to be empty and the global thread of execution complete.
```javascript
const futureDisplay = fetch(`https://someserver.com/data/alex/1`)
```
Next, at say 1ms, the constant _futureDisplay_ is declared in global memory and its value is the evaluation of **FETCH** which is a WEB API that returns a _promise_ object to be stored immediately in _futureDisplay_. This object will have three properties, _Value_, which will be set to undefined, _onFulfilled_ and _onRejected_ which will both be empty arrays. In the web browser, the **FETCH** function will also trigger a network request to get data from the address passed to it. Whenever this response gets back, the data will be stored in the Value property of the promise object, replacing its previous ‘undefined’ value.
```javascript
futureDisplay.then(display)
```
On the next line, the request is sent to the address. The data response can come back at anytime, so we need JavaScript to somehow automatically use the data when it is returned. This is where the _onFulfilled_ property on the _promise_ object comes in. We can slide a function into the _onFulfilled_ array, and when the _value_ property is filled, the function is executed with the contents of the _value_ property as input. The **.then** method is what is used to push the _display_ function into the _onFulfilled_ property on the promise object.
```javascript
runFor300ms()
```
1. At 2ms, we execute the function _runFor300ms_, create a brand new execution context, and push the function into the _call stack_. This block of code could be a for loop of some sort that will run for 300ms. Meanwhile, at say 250ms, the network request that was triggered as a result of calling the **FETCH** function resolves and responds with a string _‘Hello’_. This string will replace ‘undefined’ as _futureDisplay_’s value property. The function _display_ will be returned from the _onFulfilled_ object and stored in the micro-task queue where it will wait to be executed.
2. _runFor300ms( )_ is done executing and is popped off the call stack.
```javascript
console.log(`I am first`) 
```
1. The last line executes and the console logs  _‘I am First’_.
2. At say 303ms, the Event Loop checks that the call stack and the global execution context are empty. The micro-task queue has priority over the callback queue, so the Event Loop checks it to see if anything needs to be run. It finds the _display_ function sitting pretty there waiting to be run, and pushes it into the call stack to be executed. The function executes and the string _‘Hello’_ is printed.
3. The event loop then checks the callback queue, where it finds _sayHi_ waiting patiently. It pushes it into the call stack to be executed. Upon execution, it prints _‘Hi’_.
4. Our output will be in the order

```
'I am First'
'Hello'
'Hi'
```


##Conclusion

Remember the promise object has an _onRejected_ property which is also an empty array? Any function stored in this array will be run if the network request fails. This is used for error handling, and functions are pushed into this array using the **.catch** method.

Promises, WEB APIs, the event loop, micro task and callback queues constitute Asynchronous JavaScript which is the spine of the modern web. It provides us with functionality that allows us not have to wait in a single thread and block further code from running.