Promise in Javascript
Tags: javascript, asynchronous, web, api
Published: 2021-05-26 09:55:36

In the previous post, we talked about [Asynchronous Javascript](https://dev.to/ayushcodes/asynchronous-javascript-4a2). In this article you will learn:
- What are promises?
- What is fetch API?
- How and why fetch works differently than other web APIs like setTimeout?
- What is Microtask Queue and how it is different from Callback Queue?

--- 

## What is a Promise?
A promise is a special kind of object in javascript that lets asynchronous methods return values like synchronous methods, i.e, it gets returned immediately when we make a call to a web API like `fetch` to supply the final value at some point in the future.

We also attach functionality to the promise object that gets automatically triggered when that value comes back in the javascript from the browser API and that value would also be the input of that function.

## What is fetch API?
Suppose you are building a Weather application that displays the weather of a city/country on search. Let's say the UI is done, now comes the main part - the weather data. Here's what you might need -

- The app should be able to get the data from a server.
- When the data arrives, the app should display it.
- If the data fails to arrive, you would still want to display something like an error message. 

Javascript doesn't know how to interact with the outer world a.k.a Internet. You know from the [Asynchronous Javascript](https://dev.to/ayushcodes/asynchronous-javascript-4a2) post that this is where Web APIs shine.

Fetch is a Web API that provides an interface for fetching data. Let's see how fetch works.

## Why fetch is different than setTimeout?
Fetch works differently than the web APIs we discussed earlier like `setTimeout` because it not only initiates a background browser functionality but also immediately returns a placeholder object known as `Promise`.

## How fetch works under the hood?
Consider the code below:

```js
function display(data){
    console.log(data);
}

const upcomingData = fetch('https://getWeatherData.com/temp/seattle'); 
upcomingData.then(display);

console.log('Me first??');
```
`upcomingData` would be the return value of the `fetch('https://getWeatherData.com/temp/seattle')` Fetch returns an object with the initial value `undefined` and another *hidden* property `onFulfilled` that is an empty array. This special object runs all the functions provided inside the `onFulfilled` array when the value gets updated.

Fetch sets up XHR i.e, *XMLHttpRequest* in the browser which retrieves the data from the URL. Now while fetch was getting the data from the `getWeatherData` servers, javascript continues to execute the next line of code because the task was asynchronous.

Now on the next line, we have `upcomingData.then(display)`, if I were to ask you what this line is doing, you would most probably tell that 'when we get upcomingData, then call display function'. At least this was what I had in my mind before. But this is a wrong explanation.

Remember earlier I said that there is a *hidden* array called `onFulfilled`. Well, the method `then` will take the argument `display` which is a function definition, and push it inside the `onFulfilled` array, and on updating the placeholder value of the promise object, all the functions inside the `onFulfilled` array will get run automatically.

### 🤔 Quick doubt - Why use `then`, why not `onFulfilled.push()` ?
Because it's not a normal array, remember it's a hidden array. That's why you can't use the `push()` method on the `onFulfilled` array.

Now on the next line, `Me first??` would be logged to the browser console. Now all of our synchronous code, but the fetch was doing its background work to get the temperature of Seattle city from the server. Let's say it comes back with a response with a value of `12°C`, which updates the value of upcomingData object to `12°C`, which triggers `display` function to run with input `12°C`. Hence, now `12°C` is logged to the console.

This is how the output would look like:

```
Me first??
12°C
```
## What if the server fails to send back the data?
Just like `onFulfilled`, there is `onRejected` array also, which auto triggers any function inside it when the promise is not resolved. And you would pass the error handling function inside of `onRejected` through another method called `catch()`. For example:

```js
upcomingData
    .then(display)
    .catch(handleRejected);
```
This is known as promise chaining.

That's how fetch works under the hood. Now since you know that, let's see one more example:

```js
function display(data){
    console.log(data);
} 
function printHello(){
    console.log('Hello');
}
function blockFor300ms(){ 
    // blocks js thread for 300ms with long for loop
}

setTimeout(printHello, 0);

const upcomingData = fetch('https://getWeatherData.com/temp/seattle'); 
upcomingData.then(display);

blockFor300ms();

console.log('Me first??');
```
Our first 3 blocks of code are 3 function definitions, so javascript will declare the functions and store their entire definition in the memory line by line.

Now we hit our first obstacle, `setTimeout` which starts a timer in the browser for 0 ms, which is completed instantaneously. Hence, at 0ms, the function `printHello` is added to Callback Queue and `setTimeout`'s work is done, but the Event Loop won't let it run because there is still out global code to run.

Now, on the next line, we have `upcomingData`, so javascript would declare a constant `upcomingData` and make it `undefined` because its value is not defined yet, i.e, fetch hasn't returned a value yet. Fetch initially returns an empty object a.k.a Promise with the value `undefined` and onFulfilled empty array. But its work isn't done yet because it will also do some background browser work of getting the data from the server and when it retrieves the data, it will update the value property on the promise object.

The data retrieving work was going on in the background while we execute the next line of code, we are calling `then()` on `upcomingData` and passing in the `display` which will pass the `display` inside the onFulfilled array and whenever the value of the promise object gets updated, the `display` function would be triggered to run. But it isn't called yet.

Now the next line of code will block the further code execution for 300ms, i.e, it would be pushed on the Call stack for 300ms.

While it was there, fetch gets back the data from the servers and updates the value of the promise object to `12°C` which triggers `display` to run. But it is not pushed into the Call Stack directly just like the callback of `setTimeout`. It is queued into a Queue. Well, it turns out like there is a *Callback Queue* that we use to queue the callback of `setTimeout`, there is another queue known as **Microtask Queue** in which functions triggered by updating the value property of promise object get queued. 

Not after 300ms, the function `blockfor300ms` is popped off the Call Stack, and the code on the next line gets executed, which logs `Me first??` onto the browser console, and all of our synchronous code is finished executing.

There are two queues with functions waiting to be executed, now comes the question:
### 🥇 Which will run first?

It turns out that Event Loop gives precedence to **Microtask Queue** over Callback Queue. It sees `display` waiting inside the Microtask Queue, hence it is dequeued and pushed into the Call Stack first, and `12°C` is logged to the console.

Now since the Microtask Queue is empty, Event Loop will check the Callback Queue, and then push `printHello` into the Call Stack and `Hello` is logged to the console window.

This is how the output of the code would look like:

```
Me first??
12°C
Hello
```

It's surprising how `printHello` gets called at the last even though it was the one waiting from the beginning. And here's an interesting thing you can do, you can never let `printHello` run by continuously queuing the Microtask Queue and starve the Callback Queue.

---

This is how fetch works under the hood and why is it different from setTimeout. If you understand this, there is pretty much nothing left in the asynchronous javascript.

If you are still with me, I want to thank you for reading it. Let me know in the comments if there's something you would like to discuss, or reach out to me on Twitter [@AyushCodes](https://twitter.com/AyushCodes), my DMs are open for you.

Happy hacking!!!

## 📖 Resources

- [MDN Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [MDN Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
- [Javascript: The New Hard Parts](https://frontendmasters.com/courses/javascript-new-hard-parts)