Asynchronous JavaScript

Asynchronous JavaScript is one of the most important concepts in JavaScript as it is deeply connected with how to run your code smoothly and efficiently. For example, there might be some potential blockage in your code when you fetch data from the server and you need to know how to handle it.
Asynchronous programming is a technique that enables your program to start a potentially long-running task and still be able to be responsive to other events while that task runs, rather than having to wait until that task has finished. Once that task has finished, your program is presented with the result.
One of the long-running tasks that you would often encounter is making HTTP requests using fetch().
Synchronous programming
To understand what asynchronous programming means better, let's look at an example of synchronous programming.
const pet = 'pug'
const statement = `I want to have a ${pet}!`;
console.log(statement);
// Output
I want to have a pug!
The above code is a synchronous program because the code is executed line by line in order from top to bottom. Another example would be:
function favAnimal(animal) {
return `My favourite animal is a ${animal}!`;
}
const animal = 'dog';
const sayFavAnimal = favAnimal(animal);
console.log(sayFavAnimal);
// Output
My favourite animal is a dog!
The above is also a synchronous program although it didn't run like the previous example. It's because favAnimal() function needed to wait for the function to finish its work and return a value before the caller can continue.
Asynchronous programming
So far by looking at some of the example codes, you may notice that the keywords to explain synchronous programming are "line by line" or "wait". So asynchronous programming is the opposite of that - no need to run a code line by line and no need to wait.
What if the task of the synchronous function takes a long time? There would be a serious problem because your program won't respond or allow your users to do anything until the task is completed. That's when you should consider implementing the asynchronous program.
Event handlers
One of the examples of asynchronous programming is event handlers. Your function (the event handler) will be called whenever the event happens, which is not a straight way and you need to wait until it happens.
Promise
Next, let's look into another example of asynchronous programming.
A promise is an object returned by an asynchronous function, which represents the current state of the operation. At the time the promise is returned to the caller, the operation often isn't finished, but the promise object provides methods to handle the eventual success or failure of the operation.
To understand how promise works, let's make an HTTP request to the server.
const fetchPromise = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
console.log(fetchPromise); // Promise {<pending>}
fetchPromise
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data[0].name))
.catch(error => console.error(`Could not get products: ${error}`));
// Output
baked beans
Let's look into the above in detail.
- We called
fetch()to make an HTTP request. - As
console.log()result shows,Promiseobject is returned. It has a state whose value ispending, which means the fetch operation is still going on. - We passed a handler function into the
Promise'sthen()method. When (and if) the server accepted and was able to handle the request, we returnresponse.json(). We can return the promise returned by json() on the firstthen(), and call the second then() on that return value. - We again call the second
then()method. Inside, we can handle the data that has been returned from the server. - If you add
catch()to the end of a promise chain, then it will be called when any of the asynchronous function calls fail. So you can implement an operation as several consecutive asynchronous function calls, and have a single place to handle all errors.
What if you would like to fetch multiple data? In that case, we can use Promise.all() method. It returns promises when they are all fulfilled. This means if any of the promises in an array is rejected, it results reject.
async and await
The async keyword gives you a simpler way to work with asynchronous promise-based code.
async function fetchData(){
try {
const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json')
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json()
console.log(data[0].name);
} catch (error) {
console.error(`Could not get products: ${error}`);
}
}
fetchData();
// Output
baked beans
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown. Here try...catch block is used for error handling instead of catch().
Conclusion
We have taken a look at what asynchronous programming means in JavaScript along with examples. This is a very important concept to understand as a JavaScript developer as it significantly affects your code performance.

