Understanding JavaScript promises
Published on
What is a promise?
A promise is an object that returns a "promise" that it will return with either a resolved value or a rejection. Regardless of what is returned, the "promise" being made is that a conclusive response will in fact take place. That response may just take a moment to be fulfilled.
Basic anatomy of a promise
Using the promise constructor, a promise can be created to give a general overview of how promises work. In the following example, I've created a promise to say hello in 3 seconds in the form of a sayHello()
function.
const sayHello = new Promise((resolve, reject) => {
const personIsNice = true;
setTimeout(() => {
return personIsNice ? resolve('hello') : reject('uh oh!');
}, 3000);
});
sayHello
.then(value => {
console.log(value);
});
.catch(error => {
console.log('Unable to say hello');
throw new Error(error);
});
As you can see, the promise constructor has a single executor
parameter that takes two functions as parameters: resolve
and reject
. You can then use .then()
to perform an operation with the resolved value or use .catch()
to do something with the rejected value, as is shown above.
To walk through the example, the promise is first created with new Promise
syntax. If personIsNice
is set to true, the promise will resolve
with a value of "hello" and if personIsNice
is set to false, the promise will reject
with a value of "uh oh!" To imitate the delay it might take while a promise is pending, the logic for determining the completed state is wrapped in a setTimeout
function that waits 3 seconds to perform this calculation. The .then()
method is then applied to sayHello
value argument in .then()
will be the result of sayHello
if the promise does in fact resolve. If the promise is rejected, .catch()
will catch the error and you can do what you wish with that error. In the case of the code above, since personIsNice
is true, "hello" will be logged after a 3 second delay.
Async/await
The above code block can also be written using async
and await
syntax.
const sayHello = new Promise((resolve, reject) => {
const personIsNice = true;
setTimeout(() => {
return personIsNice ? resolve('hello') : reject('uh oh!');
}, 3000);
});
(async () => {
try {
const hello = await sayHello;
console.log(hello);
} catch (error) {
console.error('Unable to say hello');
throw new Error(error);
}
})();
Instead of using .then()
to get the value of the resolved promise, we can wrap the logic for dealing with our resolved value in a try
block and use await
to pass the value directly to a variable, in this case hello
, which is then logged. To access the possible rejected state of our promise, we a catch
block where the error
argument will be the rejected value of the promise. And since await
cannot be used outside of a function with an async
declaration, the logic to deal with our sayHello
promise is wrapped in an immediately invoked function expression (IIFE) that has been declared as asynchronous.