---
title: "Keeping our Promises (and Callbacks)"
description: "Keeping our Promises (and Callbacks)"
published: "2016-01-21"
last_updated: "2016-01-21"
authors:
  - "Thomas Bouldin (Engineering Manager)"
categories:
  - "Launch"
  - "Web"
canonical_url: "https://firebase.blog/posts/2016/01/keeping-our-promises-and-callbacks_76"
---

# Keeping our Promises (and Callbacks)

*Published January 21, 2016 by Thomas Bouldin (Engineering Manager)*

---
Today we’re adding support for Promises in the Firebase JavaScript SDK. Our promises are [A+ compatible](https://promisesaplus.com/) and their use is entirely optional.

### What Are Promises?
Promises are an alternative to callbacks. They improve readability, simplify error handling, and decouple tasks into composable units. A Promise is a task that may not have finished yet. When a Promise's task finishes successfully the Promise is "fulfilled", otherwise it is "rejected." You interact with a Promise by calling its `then` method with callbacks that should be executed when the Promise is fulfilled or rejected.

Let's demonstrate the differences between callbacks and promises by building part of a blog webapp. Our first step is to fetch an article’s contents. Here is how it might look with callbacks:

```js
ref.child('blogposts').child(id).once('value', function(snapshot) {
  // The callback succeeded; do something with the final result.
  renderBlog(snapshot.val());
}, function(error) {
  // The callback failed.
  console.error(error);
});
```

The Promise-based implementation is similar:

```js
ref.child('blogposts').child(id).once('value').then(function(snapshot) {
  // The Promise was "fulfilled" (it succeeded).
  renderBlog(snapshot.val());
}, function(error) {
  // The Promise was rejected.
  console.error(error);
});
```

When your task has only one step, Promises and callbacks are almost identical. Promises shine when your task has multiple steps.

#### Promises are Composable
Promises are most useful when you compose them. The `then` method returns a new Promise and that Promise’s return value comes from the functions passed to then. Let’s create a simple utility function that fetches a blog post and returns the JS Object, not the `DataSnapshot`, at that location:

```js
// Fetch a Blog Post by ID. Returns a Promise of an actual object, not a DataSnapshot.
function getArticlePromise(id) {
  return ref.child('blogposts').child(id).once('value').then(function(snapshot) {
    return snapshot.val();
  });
}
```

Now we can use `getArticlePromise()` and we get a Promise that does more than just fetch data from Firebase. This is especially useful when you want to transform Firebase data into a model in your application. You might also notice that we completely left error handling out of our sample--more about that later. Perhaps the greatest thing about `then` is the way it handles Promises returned by the functions you pass to `then`: if your function returned a Promise, the Promise returned by `then` will resolve or reject with the same value as the Promise you return. That’s a bit dense, so let’s illustrate the idea with a code sample. We are going to expand our blog app to fetch an article and update a read counter. The callback sample starts to get complicated:

```js
let articleRef = ref.child('blogposts').child(id);
articleRef.once('value', function(article) {
  // The first callback succeeded; go to the second.
  articleRef.child('readCount').transaction(function(current) {
    // Increment readCount by 1, or set to 1 if it was undefined before.
    return (current || 0) + 1;
  }, function(error, committed, snapshot) {
    if (error) {
      // The fetch succeeded, but the update failed.
      console.error(error);
    } else {
      renderBlog({
        article: article.val(),
        readCount: snapshot.val()
      });
    }
  });
}, function(error) {
  // The fetch failed.
  console.error(error);
});
```

The code handles errors in many places and we start to see the "Pyramid of Doom," the code indents deeper with every subtask. The Promise version is shorter, its indentation is simpler, and it doesn't worry about error handling until the end:

```js
let article;
let articleRef = ref.child('blogposts').child(id);
articleRef.once('value').then(function(snapshot) {
  // The first promise succeeded. Save snapshot for later.
  article = snapshot.val();
  // By returning a Promise, we know the function passed to "then" below
  // will execute after the transaction finishes.
  return articleRef.child('readCount').transaction(function(current) {
    // Increment readCount by 1, or set to 1 if it was undefined before.
    return (current || 0) + 1;
  });
}).then(function(readCountTxn) {
  // All promises succeeded.
  renderBlog({
    article: article,
    readCount: readCountTxn.snapshot.val()
  });
}, function(error) {
  // Something went wrong.
  console.error(error);
});
```

#### Error Handling
When you "chain" Promises with the `then` method, you can ignore errors until you are ready to handle them. Promises act like asynchronous `try` / `catch` blocks. You handle a rejected Promise by passing a second function to `then`. That second function is called instead of the first function if the Promise was rejected. If you don't pass a second function to `then`, the first function isn't called and the Promise that `then` returns is rejected with the same error that the previous Promise was rejected with.

Firebase also supports a shorthand `catch` which only takes an error handler. `catch` is not part of the A+ standard, but is part of the new JavaScript built-in and most Promise libraries. Let’s demonstrate error handling by creating a `getProfilePicPromise()` utility:

```js
// Returns a Promise of a Blob
function getProfilePicPromise(author) {
  return fetch(author.profileUrl).catch(function() {
    // By returning a new promise, we "recover" from errors in the first.
    return fetch(defaultProfileUrl);
  });
};
```

In this example, any failure to get the author's profile picture is handled by getting the default profile picture. If we successfully get the default profile picture, then `getProfilePicPromise()` succeeds. Calling `catch` or passing a second function to `then` recovers from the error, just like a `catch` block in synchronous code. Promises also have a version of "rethrowing" the error: you can literally throw an error or return a rejected Promise. To create a rejected Promise call `Promise.reject(error)`.

### Advanced Topics

#### Using `Promise.all()`
The helper function `Promise.all()` takes an array of objects which can be Promises or regular values; the Promise returned by `all()` resolves to an array of the results of its inputs once they are all ready. We can use this to let our code do multiple things at once. Let’s expand our Promise-based sample once more by letting users "star" their favorite articles:

```js
let getArticle = getArticlePromise(id);
// After we get the article, automatically fetch the profile picture
let getProfilePic = getArticle.then(function(article) {
  return getProfilePicPromise(article.author);
});

// We can find out whether the article is starred without waiting on any other task.
let getIsStarred = false;
let authData = ref.getAuth();
if (authData) {
  let isStarredRef = ref.child('userStars').child(authData.uid).child(id);
  getIsStarred = isStarredRef.once('value').then(function(snapshot) {
    return snapshot.val() != null;
  });
}

// Run all the requests then render the results.
Promise.all([getArticle, getProfilePic, getIsStarred]).then(function(results) {
  renderBlog({
    article: results[0],
    profilePic: results[1],
    isStarred: results[2],
  });

  // We’ve fetched everything; increment the read count.
  return ref.child('blogposts').child(id).child('readCount').transaction(function(current) {
    return (current || 0) + 1;
  });
});
```

This code sample fetches an article and a profile picture for the article’s author (with support for fetching a default image) in sequence. While that sequence is happening, we fetch whether the current user has starred the article in parallel. When all information is fetched, we increment a read counter. The callback-implementation is sufficiently more complicated and is left as an exercise for the reader.

### Updating Your Code
If you copy the samples in this post, be aware that they use some newer JavaScript built-ins: the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and the [Promise class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). Firebase APIs return a Promise that works in all browsers. If you want to create your own Promises, consider using a library like [Q](https://github.com/kriskowal/q). These Promise libraries let you write code that works on browsers that don't have the official Promise class yet.
