Just Learn Code

Simplify Your Asynchronous JavaScript with Promises and async/await

Introduction to Promises in JavaScript

JavaScript is a popular programming language used extensively for web development. However, JavaScript is a single-threaded language, which means it can only execute one task at a time, leading to the infamous “Callback Hell” problem.

Asynchronous tasks, such as retrieving data from a server or handling user input, further complicate matters by potentially halting the entire program until the task is completed. Fortunately, ES6 introduces a feature called promises that help manage asynchronous tasks and simplify code structure.

In this article, we will explore what promises are and how they work in JavaScript, along with some limitations to the single-threaded approach and the use of the setTimeout() function.

Limitations of single-threaded JavaScript and setTimeout() function

JavaScript, by default, is single-threaded. This means that only one task can be executed at a time, causing the program to halt its execution until that task is finished.

This limitation is especially noticeable when asynchronous tasks are involved, as regular function calls will wait for the response before executing the next line of code. One approach used to tackle the problem was the use of the setTimeout() function.

The setTimeout() function delays the execution of a function for a certain amount of time, giving the program time to execute other tasks while waiting for a response. However, this approach requires the use of nested callbacks, leading to unreadable and complicated code.to promises as a solution for asynchronous tasks

Promises, introduced in ES6, provide a way to manage asynchronous tasks by letting developers create a sequence of actions that occur once the task is complete.

Promises allow code to remain readable, and they provide a better understanding of what is happening in an asynchronous call.

Creating a Promise class object with resolve and reject arguments

Promises follow a strict pattern and have three states: Pending, Fulfilled, or Rejected. They consist of a Promise constructor that takes a single callback as its argument, with the callback containing two arguments, “resolve” and “reject.” When the Promise constructor executes, it returns a Promise object that immediately starts in a “Pending” state.

Use of async and await keywords in promises

ES6 also introduced two new keywords to simplify Promises: async and await. The async keyword is used to define an asynchronous function, and it allows the function to implicitly return a Promise object.

The await keyword, on the other hand, is used to halt the execution of the current function until the Promise object resolves. Three stages of Promises: pending, fulfilled, and rejected

Promises have three stages: Pending, Fulfilled, and Rejected.

When a Promise is created and executed, it starts in the “Pending” state, meaning that the asynchronous function call has started, but no data has yet been returned. Once the task has been completed, the Promise transitions to either “Fulfilled” or “Rejected” depending on the result of the task.


In conclusion, Promises provide a solution to the Callback Hell problem encountered when dealing with asynchronous tasks in JavaScript. They allow developers to streamline code, providing a roadmap of actions that occur after a task has been completed.

With the introduction of the async and await keywords, Promises are now more straightforward and more natural to implement than before. Understanding the three states of Promises will allow developers to write efficient and readable code while taking advantage of the asynchronous nature of JavaScript.

Implementing Promises Using async and await Keywords in JavaScript

In the previous section, we introduced Promises and explored the different stages they go through, namely “Pending,” “Fulfilled,” and “Rejected.” We also mentioned that Promises can be made more elegant and straightforward using the async and await keywords introduced in ES6. In this section, we will go into more detail on how we can use async and await to implement Promises.

Use of async keyword to create an asynchronous function

The async keyword is used to create an asynchronous function in JavaScript. An asynchronous function returns a promise that is pending when the async function is called.

When the asynchronous work is finished, the promise is resolved with a value, which could be anything from a string, object, a number, or another Promise. For instance, let’s look at a simple example of an async function that returns a string:


async function getString() {

return ‘Hello, World!’;



In the above example, the getString() function is asynchronous and returns a Promise that resolves to the string “Hello, World!”.

Use of await keyword to wait for Promise resolution

Now that we have an async function, we can use the await keyword to wait for that function to resolve before moving onto the next step. The await keyword is used inside an async function to wait for the result of a Promise.

Here is an example that combines the async and await keywords:


async function getName() {

return new Promise((resolve, reject) => {

setTimeout(() => {


}, 2000);



async function printName() {

const name = await getName();





In the above example, we have two asynchronous functions – getName() and printName(). getName() returns a new Promise that resolves after two seconds with the string value “John”.

printName() waits for the resolution of the Promise returned by getName() and once that is successful, it logs the value to the console.

Example of implementing promises to fetch data from an API

In addition to using the async and await keywords, Promises can also be used in conjunction with the fetch() function to retrieve data from an API. The fetch() function is a built-in method that allows us to make HTTP requests and returns a Promise that resolves with the response.

Here is an example of how we can use Promises with the fetch() function to get data from an API:


async function fetchData() {

try {

const response = await fetch(‘https://jsonplaceholder.typicode.com/todos/1’);

if (!response.ok) {

throw new Error(‘Network response was not OK’);


const data = await response.json();


} catch (error) {

console.error(‘There was a problem with the fetch operation:’, error);





In the above example, we have an async function fetchData() that uses the fetch() function to get data from a fake JSON API. We use the await keyword to wait for the response and then use the response.ok property to check if the response is successful.

If not, we throw an error. We then use the response.json() method to extract the JSON data and log it to the console.

In addition to logging the data to the console, we have also added a catch block to handle any errors that may occur in the fetch operation.


In conclusion, Promises are an essential part of asynchronous programming in JavaScript. The use of the async and await keywords simplifies working with Promises and makes asynchronous programming more natural and easier to read.

Combining Promises with fetch() offers a powerful mechanism for making HTTP requests and retrieving data from APIs.

In conclusion, Promises and the async/await keywords introduced in ES6 have simplified asynchronous programming in JavaScript, making it easier to read and maintain. The await keyword helps to wait for the resolution of a Promise, while the async keyword creates an asynchronous function that returns a Promise.

Moreover, combining Promises with fetch() provides an excellent way to get data from an API. The use of Promises ensures that errors are handled correctly and data is retrieved efficiently.

As such, being familiar with Promises is essential for any JavaScript developer looking to write readable and efficient code.

Popular Posts