WTF is a Promise?

First Published: 16 February 2017
Updated on: 18 June 2019

Promises are a big part of JavaScript, especially when you’re building cloud-connected applications since they are often used when fetching a JSON API or doing AJAX work, I’m going to use this post to explain why.

What is a Promise

A promise is something that will happen between now and the end of time, it’s something that will happen in the future, but not immediately. (I took that definition from Wes Bos’ course ES6 for Everyone, you should check it out.)

But what does that mean?

To understand this, you’ll need to understand something else first, JS is almost entirely asynchronous, this means that when you call a function it doesn’t stop everything to run that function.

It will keep running the code below that function even if the function hasn’t been completely executed yet.

To explain this better let’s look at a simple example, let’s say you’re logging in a user, and after login the user you want to log the user and a random string to the console.

firebase.auth().signInWithEmailAndPassword('email', 'password');
console.log(firebase.auth().currentUser);
console.log('This is a random string');

If you come from a different language (I come from python and this still give me problems) you’d expect the code to work like this:

  • It logs the user in.
  • It logs the current user to the console.
  • It logs the random string to the console.

But that’s not what’s going on since JS is asynchronous, it’s actually doing something like this:

  • It calls the function to log the user in.
  • It logs null or undefined because there’s no user yet.
  • It logs the random string to the console.
  • It finishes logging the user in.
  • It updates the log to the console to reflect the new user (sometimes).

It is just basically running everything it can find without waiting for it to complete.

That’s where the Promise come in if a Promise could talk it would tell you something like:

Hey, I don’t have the data right now, here’s an IOU and as soon as the data is back I’ll make sure to give it to you.

And you can catch those promises with .then(). So in the above example, if we wanted things to happen in this order:

  • It logs the user in.
  • It logs the current user to the console.
  • It logs the random string to the console.

We’d have to write it this way:

firebase
  .auth()
  .signInWithEmailAndPassword('email', 'password')
  .then(user => {
    console.log(user);
    console.log('This is a random string');
  });

That way JS is waiting until the function is actually completed before running the rest of the code.

Another example from Firebase would be sending a user to a new page on login, if you know nothing about promises you might write something like this:

firebase.auth().signInWithEmailAndPassword('j@javebratt.com', '123456');
this.navCtrl.setRoot(HomePage);

This makes sense right? Log the user in, and then set the HomePage as root, and in most cases, you won’t even notice there’s a problem there.

But what that is doing is actually calling the login function and immediately sending the user to the HomePage without waiting for the login’s response, so basically, you’re letting someone into your house without knowing if that person has permission to go inside.

Instead, we’d write something like this:

firebase
  .auth()
  .signInWithEmailAndPassword('j@javebratt.com', '123456')
  .then(user => {
    if (user) {
      this.navCtrl.setRoot(HomePage);
    } else {
      this.navCtrl.setRoot(LoginPage);
    }
  });

So, when the login function returns, check if there’s a real user there, and then send him to the HomePage, if not he should stay in the LoginPage.

Create your own Promises

You don’t have to rely on Promises being baked into almost everything in JS, you can also make your own promises, let’s say you are writing a data provider or service and you want to pull some data from Firebase (yeah, I know it returns a Promise by default), but instead of returning Firebase’s promise to the class, what if you want to manipulate the data and then return it?

Then it is as easy as

logUserIn(email: string, password: string): Promise {
  firebase.auth().signInWithEmailAndPassword(email, password)
  .then( user => {
    return new Promise( (resolve, reject) => {
      if (user) {
        user.newPropertyIamCreating = "New value I'm adding";
        resolve(user);
      } else {
          reject(error);
      }
    });
  });
}

Right there you’re catching Firebase’s promise, modifying the user object and then returning a new promise with the modified object (or returning an error).

So when you need to call that function from the LoginPage you could do something like this:

this.authDataProvider.logUserIn('j@javebratt.com', '123456').then(user => {
  console.log(user);
});

And then in the console, you’ll get something similar to this:

userId: {
  "email": "j@javebratt.com",
  "provider": "password",
  "...
  ...
  ..."
  "newPropertyIamCreating": "New value I'm adding"
}

And that’s it, now you can add new properties or modify responses with your own promises.

That was my short intro to Promises, hope you learned as much or more than I learned while researching for this :)