DEV Community

Codecupdev
Codecupdev

Posted on

Introducing Promises in JavaScript

If you would like to see a video of this article it is available below.

What is asynchronous?
Usually, when you hear about promises in JavaScript, you also hear the word asynchronous. What is asynchronous? First, we have synchronous which means something which is performed step by step. When you are walking you put one foot in front of the other and you don’t do both at the same time unless you are jumping! Another example is waiting for a kettle to boil before you make a cup of tea. Asynchronous on the other hand means you can do other things in the background without everything stopping and waiting. It’s a bit like saying you might watch some tv whilst you wait for the kettle to boil as opposed to standing and staring at the kettle waiting on it.

JavaScript is what we call a single-threaded language, this means only one thing can happen at once and at one time. Asynchronous JavaScript is the way in which background tasks (such as requests to servers) can happen without everything grinding to a halt due to waiting for a single task to complete. It means that the asynchronous tasks get run outside of the main flow of the program.

Introducing promises
In your day-to-day life, you often promise people something in advance of actually doing it. Perhaps you said, “I promise I will clean the dishes,” or, “I promise I will buy some milk.” This is essentially how promises in JavaScript work. When you use a promise, you are usually writing asynchronous code and you are making a promise or a transaction for something that is going to be done.

Once the promise is done, then the task is either fulfilled or failed. This is like you either fulfilled your promise of buying milk or you forgot so your promise failed.

There are two parts to understand when you are working with promises. Creating the promise and then how to use the promise.

Creating a promise
A promise is a constructor function so you must use the new keyword and a promise becomes Promise when you create one. The promise takes a function as the argument with two parameters: resolve and reject.

Resolve and reject are functions that can be called so they need to be executed with parentheses. Resolve and reject get used to determine what happens when the promise runs. Let’s look at the basic syntax for creating a promise.

const ourPromise = new Promise((resolve, reject) => {
});
console.log(ourPromise);
Enter fullscreen mode Exit fullscreen mode

In the above example, we use const and declare a variable called ourPromise. Initially, this is uninitialised but then we use the keywords new and Promise (promise is a constructor function). We pass in the resolve and reject parameters.

Promise states
There are three states which promises can have. Pending, fulfilled and rejected. The ourPromise we created does not resolve or reject anything so it will remain indefinitely in the pending state. It’s a bit like someone waiting on you to go out and buy your milk.

To complete a promise, we use resolve or reject. Resolve means that the promise succeeds and reject means it fails. Any argument can be passed into resolve and reject but often when we work with promises we are making data requests so it is an object that you would extract some data from.

Resolving and Rejecting
Let’s update our example to show the outcome of resolving and then rejecting the promise.

const ourPromise = new Promise((resolve, reject) => {
  resolve();
});
console.log(ourPromise);
Enter fullscreen mode Exit fullscreen mode
const ourPromise = new Promise((resolve, reject) => {
  reject();
});
console.log(ourPromise);
Enter fullscreen mode Exit fullscreen mode

When we resolve our promise the state becomes fulfilled. When we reject it the state becomes rejected. Now we will also update our example so it better represents a request.

const ourPromise = new Promise((resolve, reject) => {
  let didGetMilk = true;

  if(didGetMilk) {
    resolve("We got the milk");
  } else {
    reject("Ooops we did not get the milk");
  }
});
console.log(ourPromise);
//Returns ---> Promise {<fulfilled>: 'We got the milk'}
Enter fullscreen mode Exit fullscreen mode

In the above example, we create a variable called didGetMilk which can fake a response from a server. We are setting this to true for demonstration purposes. We then use an if/else statement which resolves or rejects the promise with a message based on the value of the didGetMilk variable.

When we run this because didGetMilk is true the promise gets resolved with the message. If we set didGetMilk to false the promise would be rejected as shown in the example below.

const ourPromise = new Promise((resolve, reject) => {
  let didGetMilk = false;

  if(didGetMilk) {
    resolve("We got the milk");
  } else {
    reject("Ooops we did not get the milk");
  }
});
console.log(ourPromise);
//Returns ---> Promise {<rejected>: 'Ooops we did not get the milk'}
Enter fullscreen mode Exit fullscreen mode

Using promises and understanding then
We can use then to run code once the promise has been resolved. Then is a method which will be executed immediately after the promise has been fulfilled.

We can pass a callback to then which has the code which will be run once the promise is fulfilled. Let’s update our example to show this.

const ourPromise = new Promise((resolve, reject) => {
  let didGetMilk = true;

  if(didGetMilk) {
    resolve("We got the milk")
  } else {
    reject("Ooops we did not get the milk");
  }
});
ourPromise.then(res => {
  console.log(res, "RES");
});
console.log(ourPromise);
//Returns ---> 
Promise {<fulfilled>: 'We got the milk'}
We got the milk RES
Enter fullscreen mode Exit fullscreen mode

In the above example, we set didGetMilk back to true so the promise will be resolved. We go on to use the then method on our promise. We set a parameter res for the result and we console log the result of this.

When the promise runs we get the fulfilled status but we also see the res parameter printed. The res gets passed from the argument we give to the resolve method. Let’s change the argument we give to resolve to solidify our understanding of this.

const ourPromise = new Promise((resolve, reject) => {
  let didGetMilk = true;

  if(didGetMilk) {
    resolve({message: "We got the milk"})
  } else {
    reject("Ooops we did not get the milk");
  }
});
ourPromise.then(res => {
  console.log(res.message, "RES");
});
console.log(ourPromise);
//Returns ---> 
Promise {<fulfilled>: 'We got the milk'}
We got the milk RES
Enter fullscreen mode Exit fullscreen mode

In the above example we change the argument we pass to resolve to be an object. The object has a message key with the string as the value. We update the console log of the then callback to print the message from the object.

Catch
When the promise gets rejected we handle this by using catch. It works in a similar way to when we use then for resolving the promise. Catch will be executed immediately after the promise is rejected. Let’s look at an example.

const ourPromise = new Promise((resolve, reject) => {
  let didGetMilk = false;

  if(didGetMilk) {
    resolve({message: "We got the milk"})
  } else {
    reject("Ooops we did not get the milk");
  }
});
ourPromise
.then(res => {
  console.log(res.message, "RES");
})
.catch(error => {
  console.log(error);
})
console.log(ourPromise);
//Returns ---> 
Promise {<rejected>: 'Ooops we did not get the milk'}
Ooops we did not get the milk
Enter fullscreen mode Exit fullscreen mode

This time when the code runs the promise gets rejected so the code in the catch gets run and we get the argument we passed to the call to reject printed to the console.

I hope you enjoyed this article, please feel free to post any comments, questions, or feedback, and follow me for more content!

Top comments (0)