Bootcamp
Search…
📅
Course Schedule
0: Language and Tooling Teaching Guide
1: Frontend Basics Teaching Guide
2: Backend Basics Teaching Guide
3: Backend Applications Teaching Guide
4: Backend Structure Teaching Guide
5: Full-Stack Applications Teaching Guide
6: Frontend Infrastructure Teaching Guide
7: React Teaching Guide
8: Advanced React Teaching Guide
9: Advanced Topics Teaching Guide
🧮
Algorithms Teaching Guide
💼
Interview Prep Teaching Guide
☺
User Experience Teaching Guide
0.8: JS Promises

Introduction

Promises are a JavaScript tool to avoid many levels of nested callbacks for asynchronous logic. To achieve this, Promises allow us to run certain logic only after a Promise "resolves", meaning the asynchronous functionality is complete, and we can "chain" this logic so that the logic reads sequentially instead of nested.
We will first look at the usage of Promises with .then, the most common way to use Promises, and then we'll review how to create Promises ourselves.

Example: Axios

​Axios is a Promise-based HTTP library that allows us to make arbitrary HTTP requests in code. Axios is Promise-based in the sense that Axios functions return Promises, allowing us to run certain logic only when the Promises resolves, i.e. when the request is completed.
To set up the example, we install Axios via NPM.
1
npm install axios
Copied!

.then Method

The function axios.get returns a Promise, on which we then use the .then method to perform certain logic only when the request is complete, i.e. when we receive a response. 3rd-party asynchronous functions such as axios.get often have Promise support, where we can depend on the functions to return Promises such that we can use .then logic. 3rd-party libraries will document whether they support Promises.
The following code sends a request, then console.logs the response when the response is received.
1
import axios from 'axios';
2
​
3
// Make a request
4
axios.get('http://dog.ceo/api/breeds/image/random').then((response) => {
5
// Handle request success
6
console.log(response);
7
});
Copied!
The previous code can be rewritten as follows for a clearer breakdown of how .then works.
1
import axios from 'axios';
2
​
3
// Make a request
4
const getRequestPromise = axios.get('http://dog.ceo/api/breeds/image/random');
5
​
6
// Define the callback
7
const whenRequestHasResponse = (response) => {
8
// Handle request success
9
console.log(response);
10
};
11
​
12
// Tell the program to call the callback on request success.
13
getRequestPromise.then(whenRequestHasResponse);
Copied!

Sequential, not Nested Callbacks

One of the worst parts of JavaScript callbacks is the fact that if you want four things to happen in order, you have to nest them. They become unreadable when you have many code blocks inside of other blocks. With Promises you can keep everything to mostly 1 level of nesting.
Here is an example of 3 sequential requests that would have required 3 levels of nested callbacks without Promises. myAddr variables are fictitious. .then functions always return a promise, no matter what is returned from their inner callback. More on this behaviour here.
1
axios
2
.get(
3
`https://maps.googleapis.com/maps/api/geocode/json?&address=${myAddr1}`
4
)
5
.then((response) =>
6
axios.get(
7
`https://maps.googleapis.com/maps/api/geocode/json?&address=${myAddr2}`
8
)
9
)
10
.then((response) =>
11
axios.get(
12
`https://maps.googleapis.com/maps/api/geocode/json?&address=${myAddr3}`
13
)
14
)
15
.then((response) => console.log(response));
Copied!

Creating Promises

It's rare to create Promises unless we are building a library, but knowing some of the mechanics can be helpful.
Promise is a built-in JavaScript "class". To create a Promise, we use new Promise(<CALLBACK>) syntax, where the parameter to the Promise "class constructor" is a callback function that takes 2 parameters: resolve and reject. The callback function typically invokes asynchronous functionality, and resolve and reject are functions that should get called when the asynchronous functionality completes successfully or fails to complete respectively. A call to resolve is what triggers the .then callback where the Promise is used. A call to reject will trigger a .catch callback where the Promise is used, if .catch is specified.
In the following example, we call resolve when the timeout is finished and it kicks off the .then callback where myFirstPromise is used. Note that we do not have an error case that calls reject. For proper error handling, we would call reject on error and catch it where the Promise is used with a .catch block. More information on Promise error handling here.
1
console.log('creating promise');
2
const myFirstPromise = new Promise((resolve, reject) => {
3
// We call resolve(...) when what we were doing asynchronously was successful.
4
// We call reject(...) when what we were doing asynchronously failed.
5
// In this example, we use setTimeout(...) to simulate async code.
6
// In reality, you will probably be using something like AJAX.
7
console.log('setting timeout');
8
setTimeout(() => {
9
console.log('timeout done, calling resolve');
10
resolve('Success!'); // Yay! Everything went well!
11
console.log('done calling resolve');
12
}, 250);
13
console.log('done setting timeout');
14
});
15
​
16
console.log('about to set .then callback');
17
myFirstPromise.then((successMessage) => {
18
// successMessage is whatever we passed into the resolve(...) function above.
19
// It doesn't have to be a string, but if it is only a succeed message, it probably will be.
20
console.log(`Yay! ${successMessage}`);
21
console.log('done calling .then');
22
});
23
console.log('done setting then callback');
Copied!
Last modified 2mo ago