Understanding Javascript Promises a Guide to Asynchronous Programming
Tags: webdev, javascript, programming, frontend
Published: 2024-04-29 19:54:52

---
canonical_url: https://antondevtips.com/blog/understanding-javascript-promises-a-guide-to-asynchronous-programming
---

## Introduction

Asynchronous programming is a must-have in modern JavaScript development, allowing developers to perform non-blocking operations, such as fetching data from a server, reading files, or executing time-consuming operations.
JavaScript **promises** are a powerful feature introduced in ES6 (ECMAScript 2015) to manage asynchronous operations more efficiently and cleanly.
This blog post is a guide to JavaScript promises, offering a clear understanding how **promises** can be used to handle asynchronous tasks in an elegant way.

## What Are JavaScript Promises?

A **Promise** in JavaScript is an object that represents the eventual completion or failure of an asynchronous operation and its resulting value.
A **Promise** is a proxy for a value that is not necessarily known when the promise is created, this value can be evaluated at some point in the future.

**Promises can be in one of three states:**
- **Pending**: The initial state of a promise. The operation has not completed yet.
- **Fulfilled**: The operation completed successfully, and the promise has a resolved value.
- **Rejected**: The operation failed, and the promise has a reason for the failure.


## Creating and Using Promises

To create a **promise**, you can use the `Promise` constructor, which has one argument - a function called the **executor**.
The **executor** function is executed immediately by the Promise implementation and it has two function parameters: `resolve` and `reject` callbacks.

```javascript
const promise = new Promise((resolve, reject) => {
    try {
        // Execute operation
        resolve("Operation succeeded");
    } catch (e) {
        reject("Operation failed");
    }
});
```

When a promise starts executing it's in the **Pending** state by default.
Later promise must be transferred to either **Fulfilled** or **Rejected** state.

`resolve` callback is used to transfer a promise to **Fulfilled** state and return a resulting value of the promise as parameter.
`reject` callback is used to transfer a promise to **Rejected** state and return a failure result of the promise as parameter.

There are 2 ways to get the **promise** result:
- using `then()` and `catch()` functions that hook to the promise
- using `async/await` statements

## Get Promise Result Using then() and catch() Functions

To get a result from a promise, you can call `then()` function for success scenarios and `catch()` function for handling failures.
For example:

```javascript
promise
    .then(result => {
        // "Operation succeeded" if successful
        console.log(result);
    })
    .catch(error => {
        // "Operation failed" if an error occurred
        console.error(error);
    });
```

You can chain these methods to perform additional operations after the previous **promise** has completed.

```javascript
function firstPromise() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("First promise finished with result: 1");
            resolve(1);
        }, 1000);
    });
}

function secondPromise(previousResult) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("Second promise finished with result: ", previousResult + 1);
            resolve(previousResult + 1);
        }, 1000);
    });
}

function thirdPromise(previousResult) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("Third promise finished with result: ", previousResult + 1);
            resolve(previousResult + 1);
        }, 1000);
    });
}

firstPromise()
    .then(result => secondPromise(result))
    .then(result => thirdPromise(result))
    .then(finalResult => console.log("All promises completed with final result: ", finalResult))
    .catch(error => console.error("An error occurred:", error));
```

Here we chain together 3 promises executing one after another. In this example "3" is printed to console as a final result.
The final `catch()` function is called when an error occurs or `reject()` function is called in any of 3 promises.

Before the invention of **Promises** performing asynchronous operations anticipated using callbacks.
This led to a bad code structure with deeply nested callbacks, especially when using multiple asynchronous operations one after another.

Here is how the previous example will look like when using callbacks:

```javascript
function firstCallback(callback) {
    setTimeout(() => {
        console.log("First callback finished with result: 1");
        callback(1);
    }, 1000);
}

function secondCallback(previousResult, callback) {
    setTimeout(() => {
        console.log("Second callback finished with result: ", previousResult + 1);
        callback(previousResult + 1);
    }, 1000);
}

function thirdCallback(previousResult, callback) {
    setTimeout(() => {
        console.log("Third callback finished with result: ", previousResult + 1);
        callback(previousResult + 1);
    }, 1000);
}

firstCallback(function(result) {
    secondCallback(result, function(newResult) {
        thirdCallback(newResult, function(finalResult) {
            console.log("All callbacks completed with final result: ", finalResult);
        });
    });
});
```

Doesn't look pretty, right? That's why the invention of **promises** was a huge step further in asynchronous JavaScript development.
But what if I told you - that it's not the best viable option nowadays? Let's explore what is the best option.

## Get Promise Result Using async/await

`async/await` statements in JavaScript are a complete game changer in asynchronous development.
**ES2017** introduced async functions and the `await` keyword, that allow developers to write asynchronous code that looks and behaves a like synchronous code:

```javascript
async function fetchDataAsync() {
    try {
        const response = await fetch("https://jsonplaceholder.typicode.com/posts");
        const data = await response.json();
        return data;
    } catch (error) {
        console.error("Failed to fetch data: ", error);
    }
}

const data = await fetchDataAsync();
console.log(data);
```

Here an `async` function returns a `Promise<T>`, that holds a data received from the API call.
By using `await` keyword we get this data as a promise result.

After the line `const data = await fetchDataAsync();` we can simply write more code as if all operations were executed synchronously.
It looks perfect!

Now let's explore how we can update one of the previous examples where we chained 3 promises with a `then()` function, when using `async/await` statements:

```javascript
function firstPromise() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(1);
        }, 1000);
    });
}

function secondPromise(previousResult) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(previousResult + 1);
        }, 1000);
    });
}

function thirdPromise(previousResult) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(previousResult + 1);
        }, 1000);
    });
}

try {
    const firstResult = await firstPromise();
    console.log("First promise finished with result: ", firstResult);

    const secondResult = await secondPromise(firstResult);
    console.log("Second promise finished with result: ", secondResult);

    const thirdResult = await thirdPromise(secondResult);
    console.log("Third promise finished with result: ", thirdResult);

    console.log("All promises completed with final result: ", thirdResult);
} catch (error) {
    console.error("An error occurred:", error);
}
```

It looks really nice. This code is much more readable and maintainable because of using the `async/await` statement. 


## Summary

JavaScript **promises** are a vital feature for performing non-blocking operations, such as fetching data from a server, reading files, or executing time-consuming operations.
It offers a more manageable and readable approach compared to old callback-based solutions.

You can use the `async/await` syntax to write even cleaner and more efficient JavaScript code.

Hope you find this blog post useful. Happy coding!

_Originally published at_ [_https://antondevtips.com_](https://antondevtips.com/blog/understanding-javascript-promises-a-guide-to-asynchronous-programming)_._

### After reading the post consider the following:

- [Subscribe](https://antondevtips.com/blog/understanding-javascript-promises-a-guide-to-asynchronous-programming#subscribe) **to receive newsletters with the latest blog posts**
- [Download](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/frontend/javascript/promises) **the source code for this post from my** [github](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/frontend/javascript/promises) (available for my sponsors on BuyMeACoffee and Patreon)

If you like my content —  **consider supporting me**

Unlock exclusive access to the source code from the blog posts by joining my **Patreon** and **Buy Me A Coffee** communities!

[![](https://cdn-images-1.medium.com/max/233/1*GSZFx05RDUWr5pn_E9bK8w.png)](https://www.buymeacoffee.com/antonmartyniuk)

[![](https://cdn-images-1.medium.com/max/229/1*8tJk9eYCJrkzoAJw2cILSA.png)](https://www.patreon.com/bePatron?u=73769486)