Who can wait quietly while the mud settles?
Who can remain still until the moment of action?
- Laozi, Tao Te Ching
ES 2017 (ES8) introduced a new way of writing asynchronous functions.
Before we understand these Async functions, I want to recap and review the fundamentals.
We've seen callbacks
and promises
Callback Example:
setTimeout(() => {
console.log('This runs after 1000 milliseconds.');
}, 1000);
It could soon turn out to become Callback Hell:
Note: Callback Hell is a situation where callbacks are nested within other callbacks several levels deep, potentially making it difficult to understand and maintain the code.
Javascript is a single threaded language -- meaning it can only do one thing at a time.
In other words, most of the code we have written till this date is synchronous.
I really like this example to explain asynchronous versus synchronous.
You have two trains.
If we run the trains synchronously, one train can not leave the station until the other one comes back.
If we run the trains asynchronously, both trains can leave whenever they want to, as long as they come back to the station at some point
If trains aren't your thing, I'll give you another short example.
Synchronous - I'll drop you off at the store and wait till you come back
Asynchronous - I'll drop you off at the store and periodically check if you are done
We use asynchronous calls if the order the tasks are done does not matter.
For example, our phones receive updates asynchronously. It doesn't wait for facebook to update, before updating twitter. Or vice versa.
Example: We have a website that loads real time stock data from an API and then processes and formats the data to display to the user.
If we try to process and format the data before the API has fetched the desired information, we are either going to get an error or an empty blank page.
We use Promises to make sure that the API data is formatted and processed after the API call is finished.
Definition:
A Promise is an object representing the eventual completion or failure of an asynchronous operation.
A promise can have three possible states:
- Pending — Asynchronous operation has not completed yet
- Fulfilled — Operation has completed and the Promise has a value
- Rejected — Operation has completed with an error or failed.
In ES6, we learned that we could use fetch which takes in the path to the resource you want to fetch (usually a URL) — and returns a Promise
A promise is comprised of two parts
- the initial code to run (ex: fetch)
- The callback code that should be called later when the above code completes (ex: processing data, etc.)
examplePromiseFunction()
.then((result => {...))
.catch((error) => {...})
.then
is a promise method and contains a code block that is called later after examplePromiseFunction()
completes (or fulfilled).
.catch
is a promise method that contains a code block that might be called later if examplePromiseFunction()
raises an exception or is rejected.
fetch('https://real-time-stock-data.com/json')
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(finalResult);
})
.catch(failureCallback);
This could get tedious though. Chaining methods is nice, but it would be nice if we could simplify the API call.