Asynchronous JavaScript—How Callbacks, Promises, and Async-Await Work
Tags: javascript, webdev, node, frontend
Published: 2020-06-22 12:44:35

---
title: Asynchronous JavaScript—How Callbacks, Promises, and Async-Await Work
published: true
description: JavaScript touts asynchronous programming as a feature. This means that, if any action takes a while, your program can continue doing other things while the action completes.
tags: javascript, webdev, node, frontend
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/houiskx1lkc67c0dbbit.png
---

*Please give this post a 💓, 🦄, or 🔖 if it you enjoyed it!*

JavaScript touts asynchronous programming as a feature. This means that, if any action takes a while, your program can continue doing other things while the action completes. Once that action is done, you can do something with the result. This turns out the be a great feature for functionality like data fetching, but it can be confusing to newcomers. In JavaScript, we have a few different ways to handle asynchronicity: callback functions, Promises, and async-await.

<hr />

I make other easy-to-digest tutorial content! Please consider:

- Subscribing to my [DevTuts mailing list](https://buttondown.email/devtuts)
- Subscribing to my [DevTuts YouTube channel](https://youtube.com/c/devtutsco)


<hr />

# Callback Functions

A callback function is a function you provide that will be executed after completion of the async operation. Let’s create a fake user data fetcher and use a callback function to do something with the result.

## The Fake Data Fetcher

First we create a fake data fetcher that doesn’t take a callback function. Since `fakeData` doesn’t exist for 300 milliseconds, we don’t have synchronous access to it.

```javascript
const fetchData = userId => {
  setTimeout(() => {
    const fakeData = {
      id: userId,
      name: 'George',
    };
    // Our data fetch resolves
    // After 300ms. Now what?
  }, 300);
};
```

In order to be able to actually do something with our `fakeData`, we can pass `fetchData` a reference to a function that will handle our data!

```javascript
const fetchData = (userId, callback) => {
  setTimeout(() => {
    const fakeData = {
      id: userId,
      name: 'George',
    };
    callback(fakeData);
  }, 300);
};
```

Let’s create a basic callback function and test it out:

```javascript
const cb = data => {
  console.log("Here's your data:", data);
};

fetchData(5, cb);
```

After 300ms, we should see the following logged:

```
Here's your data: {id: 5, name: "George"}
```

# Promises

The Promise object represents the eventual completion of an operation in JavaScript. Promises can either `resolve` or `reject`. When a Promise resolves, you can handle its returned value with then then method. If a Promise is rejected, you can use the catch the error and handle it.

The syntax of the Promise object is as follows:

```javascript
new Promise(fn);
```

Were `fn` is a function that takes a `resolve` function and, optionally, a `reject` function.

```javascript
fn = (resolve, reject) => {};
```

## The Fake Data Fetcher (with Promises)

Let’s use the same fake data fetcher as before. Instead of passing a callback, we’re going to return a new `Promise` object the resolves with our user’s data after 300ms. As a bonus, we can give it a small chance of rejecting as well.

```javascript
const fetchData = userId => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.1) {
        reject('Fetch failed!');
      }
      const fakeData = {
        id: userId,
        name: 'George',
      };
      resolve(fakeData);
    }, 300);
  });
};
```

Our new `fetchData` function can be used as follows:

```javascript
fetchData(5)
  .then(user => {
    console.log("Here's your data:", user);
  })
  .catch(err => {
    console.error(err);
  });
```

If `fetchData` successfully resolves (this will happen 90% of the time), we will log our user data as we did with the callback solution. If it is rejected, then we will `console.error` the error message that we created (“Fetch failed!“)

One nice thing about Promises is you can chain then to execute subsequent Promises. For example, we could do something like this:

```javascript
fetchData(5)
  .then(user => {
    return someOtherPromise(user);
  })
  .then(data => {
    console.log(data);
  })
  .catch(err => {
    console.error(err);
  });
```

Furthermore, we can pass an array of Promises to `Promise.all` to only take action after all Promises are resolved:

```javascript
Promise.all([fetchData(5), fetchData(10)])
  .then(users => {
    console.log("Here's your data:", users);
  })
  .catch(err => {
    console.error(err);
  });
```

In this case, if both Promises are successfully resolved, the following will get logged:

```
Here's your data:
[{ id: 5, name: "George" }, { id: 10, name: "George" }]
```

# Async-Await

Async-await offers a different syntax for writing Promises that some find clearer. With async-await, you can create an `async` function. Within that async function, you can `await` the result of a Promise before executing subsequent code! Let’s look at our data fetch example.

```javascript
const fetchUser = async userId => {
  const user = await fetchData(userId);
  console.log("Here's your data:", user);
};
fetchUser(5);
```

Pretty nice, right? One small wrinkle: we’re not handling our Promise rejection case. We can do this with `try/catch`.

```javascript
const fetchUser = async userId => {
  try {
    const user = await fetchData(userId);
    console.log("Here's your data:", user);
  } catch (err) {
    console.error(err);
  }
};
fetchUser(5);
```

# Browser/Node Support

Since callback functions are just normal functions being passed to other functions, there’s no concern about support. Promises have been standard since ECMAScript 2015 and have decent support, but are not supported in Internet Explorer. Async-await is newer (standard since ECMAScript 2017) and is has good support in newer browser versions. Again, it isn’t supported in Internet Exporer.

- MDN - [Promise Browser Support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- MDN - [Async Function Browser Support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)

On the node side, async-await (and therefore, Promises) have been well-supported since nove v7.6.