Callback is function passed to another function that will be executed in some time based on some condition.
Why do you need a callback
Well you can't really eat undefined. Let's use callbacks to solve this problem.
Another good common example of callback used for async code is using an event listener.
Here the callback function is waiting for the user to click the document and only then it executes.
Problem with using callback
Say that we have 3 functions that needs to be executed only after the other one finishes and each of them take time does not run on the main thread (Introduces callback hell)
Promises
We can achieve the same result with much more cleaner syntax using promises.
There are always two parts to a promise, one is the promise maker and the other is the receiver (just like in real like promises)
Using callback to fetch the current weather:
Now Let's convert this in a Promise code
The getWeather() returns a promise, since all functions needs to return something otherwise it would return undefined
Its like the getWeather() saying, hey I don't have the weather yet but I promise to you that I will get you (fulfill) the data once I have it.
The Promise object takes a function and that is where all the async code goes. This function takes in 2 arguments resolve and reject, which is called if the promise is fulfilled or is failed respectively.
Now let's consume the promise using the receiver
Now the nice thing about using Promise instead of callback is :
Say we now want to get a Icon based on the weather :
So now instead of getting into a callback hell, we are just chaining the functions together and we can go as far as we like.
Another benefit of this approach is that you have the catch function to catch some errors where as in the callback case you would have to pass 2 callback function to handle the success and error.
As an exercise, try to dry-run the following code and reason what the output will be:
There's also a finally block apart from then & catch, which runs at the end no matter if the promise is fulfiled or rejected. Can use it to remove some event listeners and clear things up.
In case of chaining if you want to handle the errors of each one of the promise separately you can do that by passing a second param to the then function.
Dealing with multiple Promises
Function like Promise.all,Promise.any, Promise.race, Promise.allSettled takes in an array of promises and returns a single promise.
The then function is only called if all the promises are resolved, else calls the catch function.
Another Example: 🌟
Other methods:
Promise.any prints the 1st promise that is resolved.
To get the 1st promise that finishes (no matter if it fails or resolves) use race
There is also a allSettled that waits for each promise to finish and then prints the status of each
Notice in this case only then is ran no matter what(even if all the promises are rejected), catch is not called
There is also finally function that run in all case, where then runs or catch, finally runs for sure
Async & Await
Async & Await are just syntactical sugar to write asynchronous code that feels more like synchronous code.
Few key points
async and await are used together (Except for in JS Modules and Chrome Dev Tools, where you can you await without async)
They are used only on the receiver side and the promise maker implementation stays the same
You can await any function that returns a Promise. And hence you can use it with fetch API as well
Any function can be converted to async, using the async keyword
All async functions always returns a Promise
Use try / catch and finally blocks to handle errors & perform clean ups
Top level Await
Why did we get different outputs in each case?
Usually await is not allowed outside a async function, since in that case the async function bounds the code that will not be executed, until we receive the response. When using top level await, entire module acts as a async function, and all the code below is ran after the code with await keyword, since JS has no idea when will the await response will be used.
Which is not the case with promise version since JS knows that it will only have to wait till the chained then(), catch(), or finally() functions, and all the other code below it can run without waiting for it. And thus diffrent result.
For better undertanding please evalutate the three cases defined below: