DEV Community

Cover image for Asynchronous JavaScript: Promises Async Await!
Cybermaxi7
Cybermaxi7

Posted on

Asynchronous JavaScript: Promises Async Await!

ASYNCHRONOUS JAVASCRIPT

Before we undestand asynchronous javascript code, we need to first understand what synchronous javascript code is (basically the opposite of asynchronous code)

Synchronous Code simply means code that is executed line by line in the exact order of execution

for example

const p = document.querySelector('.p');
p.textContent = 'My name is Cybermaxi';
alert('Text set');
p.style.color = 'red';
Enter fullscreen mode Exit fullscreen mode

The above code will be executed line by line, if anything goes wrong with a line, the remaining lines of code will not run.
For example the alert method which brings out a pop-up window, if we do not click ok, the remaining lines of code will not run. This is the problem with synchronous code

Asynchronous code is however executed after a task that runs in the background finishes. The execution does not wait for an asynchronous code to finish before it runs

For example

const p = document.querySelector('.p');
setTimeout(function(){
    p.textContent = 'My name is Cybermaxi';
}, 5000);
p.style.color = 'red';
Enter fullscreen mode Exit fullscreen mode

The setTimeout function is asynchronous in that its callback function will run after timeout is completed. It doesn't block or obstructs other lines of code from executing, It simply runs on the background. Whenever the timer finishes (5 seconds), the callback function will run.

We can therefore say Asynchronous programming is coordinating behavior of a program over a certain period of time
NB Callback functions alone do not make a code asynchronous, for example the map() that contains a callback isn't asynchronous.

Example of asynchronous behavior in javascript include Geolocation API, AJAX calls etc
This brings us to AJAX.

WHAT ARE AJAX CALLS

Asynchronous Javascript and XML (AJAX) allows us to communicate with web servers in an asynchronous way. With AJAX, we can request data from web servers dynamically.

How it works

Let's say we have our web application running in our browser(client), we can request (ask for some data) from a web server a particular data we need, the web server then sends a response back to us which may contain the data we need or an error occurred while trying to get that data.
Note that when requesting, we can either GET(fetch data) or POST(send data) to the web servers. the web servers usually contains a web API

What is a web API?

API stands for Application Programming Interface. It is a piece of software that can be used by another piece of software to allow applications talk to each other.
It can also be seen as an application running on a server, that receives request for data and sends data back as response.
NB There is an API for everything!

In Javascript there are multiple ways of making AJAX calls but let's start with the oldest which is using the XMLHttpRequest();

The XMLHttpRequest() object are used to interact with servers, you can retrieve data from a url without having to do a full page reload, this enables a webpage to update a part of the page without disrupting what the user is doing.
Despite it's name, it can be used to retrieve any kind of data not just XML
E.g
const request = new XMLHttpRequest()

  1. The above line of code creates a new XMLHttpRequest object

  2. The next step is to call the open() method on the request object with the following parameters
    request.open('GET', 'https://url of the api')
    3.
    The next step is to call the send() method
    request.send();
    At this point, this is where asynchronous javascript happens. The request is sent and we wait for a response from the API, all this happens behind the scenes, thus not hindering the execution of any line of code that may come afterwards.

  3. The next step is to attach an event listener on the request object to listen for the load event then do something with the response

request.addEventListener('load', function(){
    console.log(this.responseText)
})
Enter fullscreen mode Exit fullscreen mode

Wondering where responseText came from? It is a variable name created automatically by he XMLHttpRequest containing the data we requested.
Notice the data you get will be in a string format, we therefore need to convert it into an object
const data = JSON.parse(this.responseText);

The second and major way of making request to API is the Fetch()
We simply do

const request = fetch(url);
The fetch method returns a Promise which brings us to Promises

WHAT ARE PROMISES

promises in JavaScript

  • A Promise can be seen as an object that is used as a placeholder for the future result of an asynchronous operation

  • A Promise can also be seen as a container for an asynchronously delivered value

  • In simple terms a promise is a container for a future value.
    An example of such value is a response from AJAX calls

Two (2) Advantages of Using Promises

  1. We no longer have to rely on events and callbacks passed into asynchronous functions to handle asynchronous result
  2. Instead of nesting callbacks, we can chain promises for a sequence of asynchronous operation thus escaping callback hell

Since promises work with asynchronous operations, they are time sensitive and as a result they can be in different states, this is called the Promise Lifecycle

When a promise is initiated, it is in the Pending state, the asynchronous task then gets settled and at this settled state exists two states: the fulfiled and the rejected state

  • A fulfilled state means successs, the value or response is now available
  • A rejected promise means an error has occurred, therefore a failed promise.
fetch('url').then(response => response.json())
.then(data => console.log(data))
Enter fullscreen mode Exit fullscreen mode

The fetch API returns a promise which if fulfilled, provides a response, now that response can only be accessed by calling the json() method on it. After calling it, it returns another response which inturns provide us with the data we requested for.

Building a Promise

We have been using promises but now let us create our own new promise. A promise is simply a javacript objevt and it is a constructor that accepts only one argument which is called an executor function. this function takes in two arguments which is the resolve and reject parameters

const newPromise = new Promise(function(resolve, reject){})
Use case

const lotteryPromise = new Promise(function(resolve, reject){
    console.log('Lottery has began')
    setTimeout(function(){
        if (Math.random() >= 0.5) {
            resolve('You Win');
        } else {
            reject new Error('You Lost')
        }
    }, 2000)
})
Enter fullscreen mode Exit fullscreen mode

Now let's consume the promise
lotteryPromise.then(res => console.log(res)).catch(err => console.error(err))

However we can consume promises in a more efficient way using the ASYNC AWAIT other than the then method chaining

Async Await in JavaScript

In Async Await, we declare the async keyword when defining the function to make that function an async function and then add the await keyword to any asynchronous operations like the fetch() which inturns produces a promise. The await simply means wait for the promise to be fulfiled and one beauty of this is we can be able to store the response in a variable which we couldn't do before

const getNumbers = async function() {
    const res = await fetch(url);
    const data = await res.json();

}
Enter fullscreen mode Exit fullscreen mode

Isn't this simple as to when compared with the promise then method chaining?

But what happens when we want to make or carry out multiple promises at the same time not depending on one another we can then

const getThreeNumbers = async function() {
    const data1 = await firstPromise();
    const data2 = await secondPromise();
    const data3 = await thirdPromise();
    const [result] = [data1, data2, data3];
}
Enter fullscreen mode Exit fullscreen mode

However the problem with the above code is that each promise must wait for the previous promise to fulfill before it gets executed, but if we want to execute them all at the same time, we can use what is called Promise.all() and this returns back a single promise
const result = Promise.all([
await firstPromise();
await secondPromise();
await thirdPromise();
])

Despite the length of the post, i hope you found something useful and learnt a thing or two.

Leave a comment on something you learnt and improvements or additions to my post
Thank you 😊

Top comments (0)