Skip to main content

Javascript: Promises

Intro​

Promises are a new set of functionality in Javascript that provide an alternative to repetitive nested callback function (AKA callback hell). You can read more about promises here:

Basic Syntax​

Constructor​

Promise()

The constructor is primarily used to wrap functions that do not already support promises.

let promiseObj = new Promise( tetherFunction );

tetherFunction​

The tetherFunction is the code to be executed by the constructor, and is written by the programmer.

let promiseObj = new Promise( tetherFunction(resolve, reject) {
// executor
});

Where resolve and reject are defined by the Javascript engine. There can be only result between these two, and when that condition is met, the promise has been resolved (either fulfilled or not).

Here is an alternate syntax with arrow functions.

let p = new Promise((resolve, reject) => {
// executor
});

Here is a sample promise.

var keepsHisWord;
keepsHisWord = true;
promise1 = new Promise(function(resolve, reject) {
if (keepsHisWord) {
resolve("The man likes to keep his word");
} else {
reject("The man doesnt want to keep his word");
}
});
console.log(promise1);

promise fulfilled, the man keeps his word

The promise begins in a state called pending and then it is either fulfilled or rejected.

In this case the state will be rejected if the status of keepsHisWord is false, null or undefined.

We can use simple if else statements to match the desired value of the promise.

And here is another sample Promise with arrow functions this time:

let p = new Promise((resolve, reject) => {
let a = 1+1
if (a == 2) {
resolve('Success');
} else {
reject('Failed');
}
});

Methods​

The methods are triggered when the state of the promise moves from pending to fulfilled/rejected.

.then​

The most important, fundamental one is .then.

The syntax is:

promise.then(
function(result) { /* handle a successful result */ },
function(error) { /* handle an error */ }
);

The first argument of .then is a function that runs when the promise is resolved, and receives the result.

The second argument of .then is a function that runs when the promise is rejected, and receives the error.

For instance, here’s a reaction to a successfully resolved promise:

let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("done!"), 1000);
});

// resolve runs the first function in .then
promise.then(
result => alert(result), // shows "done!" after 1 second
error => alert(error) // doesn't run
);

If we’re interested only in successful completions, then we can provide only one function argument to .then:

let promise = new Promise(resolve => {
setTimeout(() => resolve("done!"), 1000);
});

promise.then(alert); // shows "done!" after 1 second

.catch​

If we’re interested only in errors, then we can use null as the first argument: .then(null, errorHandlingFunction). Or we can use .catch(errorHandlingFunction), which is exactly the same:

let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Whoops!")), 1000);
});

// .catch(f) is the same as promise.then(null, f)
promise.catch(alert); // shows "Error: Whoops!" after 1 second

The call .catch(f) is a complete analog of .then(null, f), it’s just a shorthand.

.finally​

Finally will run regardless of whether the promise was kept or not. It is good for cleanup, like stopping a loading indicator.

.all​

This will run when all of the promises specified in an array have been fulfilled.

.race​

This will return the first Promise that completes it’s task.

const recordVideoOne = new Promise((resolve, reject) => {
resolve('Video 1 Recorded')
})

const recordVideoTwo = new Promise((resolve, reject) => {
resolve('Video 2 Recorded')
})

const recordVideoThree = new Promise((resolve, reject) => {
resolve('Video 3 Recorded')
})

Promise.race([
recordVideoOne,
recordVideoTwo,
recordVideoThree
]).then(message => {
console.log(message)
})

Examples​

Example 1: A simple promise​

let p = new Promise((resolve, reject) => {
let a = 1+1
if (a == 2) {
resolve('Success');
} else {
reject('Failed');
}
});

Going back to a good example above, what would some callback functions look like on this?

p.then((message) => {
console.log('This is in the .then ' + message);
}).catch((message) => {
console.log('This is in the .catch ' + message);
})

If the promise resolves then we will get the .then message.

If the promise rejects then we will get the .catch message.

Example 2: Replacing a callback function​

Let us first look at how this would be structured as a callback function.

function watchTutorialCallback(callback, errorCallback) {
let userLeft = false
let userWatchingCatMeme = false

if (userLeft) {
errorCallback({
name: 'User Left',
message: ':('
})
} else if (userWatchingCatMeme) {
errorCallback({
name: 'User Watching Cat Meme',
message: 'WebDevSimplified < Cat'
})
} else {
callback('Thumbs up and Subscribe')
}
}

We have defined the callback function, now we can call it.

watchTutorialCallback(message => {
console.log(message)
}, error => {
console.log(error.name + ' ' + error.message)
})

Now we can convert all this to a promise.

function watchTutorialPromise() {
let userLeft = false
let userWatchingCatMeme = false
return new Promise((resolve, reject) => {
if (userLeft) {
reject({
name: 'User Left',
message: ':('
})
} else if (userWatchingCatMeme) {
reject({
name: 'User Watching Cat Meme',
message: 'WebDevSimplified < Cat'
})
} else {
resolve('Thumbs up and Subscribe')
}
})
}

Note that we have removed the callbacks.

watchTutorialPromise().then(message => {
console.log(message)
}).catch(error => {
console.log(error.name + ' ' + error.message)
})

This is a superior syntax because if we want to stack up multiple callbacks, we would just tack on additional .then methods, instead of continuously nesting callbacks (callback hell).

Example 3: .all method​

The .all method is what executes when all promises have been resolved.

const recordVideoOne = new Promise((resolve, reject) => {
resolve('Video 1 Recorded')
})

const recordVideoTwo = new Promise((resolve, reject) => {
resolve('Video 2 Recorded')
})

const recordVideoThree = new Promise((resolve, reject) => {
resolve('Video 3 Recorded')
})

Promise.all([
recordVideoOne,
recordVideoTwo,
recordVideoThree
]).then(messages => {
console.log(messages)
})

all resolve messages

Comments

Recent Work

Free desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.

Learn More

BidBear

bidbear.io

Bidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.

Learn More