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:
- Google Developers: Promises Primer
- Javascript.info : Promise Basics
- Hackernoon: Understanding Promises
- MDN: Promise
- ποΈ WDS: Web Dev Simplified
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);
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)
})
Comments
Recent Work
Basalt
basalt.softwareFree 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.
BidBear
bidbear.ioBidbear 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.