Promise.resolve()
I have one more Promise
method to go over today, Promise.resolve()
. This method is related to Promise.reject()
in that it also is only concerned with a single Promise
(as opposed to an iterable of Promise
s). However, where Promise.reject()
is about deliberately rejecting a Promise
, Promise.resolve()
is (probably unsurprisingly) used to deliberately resolve a Promise
and define the value the resolved Promise
carries with it. This method is useful for debugging or, as we have seen throughout a bunch of my Promise
blog posts, demonstrating examples of Promise
behavior throughout a Promise
chain.
Syntax
Promise.resolve(value);
Parameters
value
- Argument to be resolved by thisPromise
. Can also be aPromise
or a thenable to resolve.
Return Value
Promise.resolve()
returns a Promise
that is resolved with the given value
. If that value
itself is a Promise
, then that Promise
is returned.
Promise.resolve("Woohoo!").then( (result) => { console.log(result); }, (error) => { console.error(error); } // not called);// Expected output: "Woohoo!"
Here's an example of basic usage of Promise.resolve()
. I've passed it the value of a string, "Woohoo!"
. It then follows the .then()
instance method. Because we are forcing a resolution, the value
we passed gets returned as the result
, and the resolve handler function just logs "Woohoo!"
. The error handler function does not run.
But now let's look at a slightly more advanced case: What would happen if the value
passed to Promise.resolve()
is itself a Promise
?
const promise1 = Promise.resolve("Hi there");const promise2 = Promise.resolve(promise1);
promise2.then( (result) => { console.log(`result: ${result}`); }, (error) => { console.error(error); });
console.log(`promise1 === promise2 ? ${promise1 === promise2}`);/* * Expected result: * promise1 === promise2 ? true * result: Hi there */
So what we're seeing in this example is that if the value given to Promise.resolve()
is itself a Promise
, then that Promise
is returned. promise2
accepts the resolved promise1
as its value, where promise1
's returned value is the string "Hi there
". I also put in a check to see whether the return values of promise1
and promise2
are strictly equal to one another. It turns out they are. Also note that this check logs its result before the .then()
handler on promise2
. This happens because Promise
handler functions are called asynchronously.
Thenables
Now, let's take a look at thenables, which is something that has a then
method.
const thenable = { then: function (onFulfill, onReject) { onFulfill("Woohoo!"); },};
const promise = Promise.resolve(thenable);
console.log(promise instanceof Promise); // Expected result: true, object casted as a Promise
promise.then( (result) => { console.log(result); }, (error) => { console.error(error); } // not called);// Expected result: "Woohoo!"
In this example I've defined an object and saved it to the variable thenable
. This has one method named then
. This is a function that accepts two callback functions as its parameters, named onFulfill
and onReject
, and calls onFulfill
with the string value "Woohoo!"
.
Below that, I've defined a variable named promise
and its value is the result of Promise.resolve()
. I've passed the thenable
object as Promise.resolve()
's value
argument.
Below the promise
definition, I'm checking whether the value returned by promise
's Promise.resolve()
method is an instance of a Promise
. This returns true
, demonstrating that an object with a then
method actually gets casted as a Promise
when it gets passed to Promise.resolve()
.
Finally we can follow the then
method in the thenable object, logging out the result value as usual, giving us the string "Woohoo!"
.
Now I'm going to slightly modify this code to see what happens when the thenable throws an error before its callback function runs.
const thenable = { then: function (onFulfill) { throw new TypeError("Throwing an error"); onFulfill("Woohoo!"); },};
const promise = Promise.resolve(thenable);promise.then( (result) => { console.log(result); }, // not called (error) => { console.error(error); });// Expected result: TypeError: Throwing an error
This function throws a TypeError
with the message "Throwing an error"
. This error is thrown before the onFulfill
callback gets called.
We then pass thenable
as the value for Promise.resolve()
and assign that to the variable promise
. When we follow the .then()
instance methods on promise
, the error handler function logs the thrown TypeError
. The resolve handler ((result) => { console.log(result) },
) is not called. This happens because we threw the TypeError
before the callback function inside of the thenable then
method.
By contrast, let's throw the error after the callback function:
const thenable = { then: function (onFulfill) { onFulfill("Woohoo!"); throw new TypeError("Throwing an error"); },};
const promise = Promise.resolve(thenable);promise.then( (result) => { console.log(result); }, (error) => { console.error(error); } // not called);// Expected result: "Woohoo!"
This code is exactly the same except the onFullfill
callback method is called before the TypeError
is thrown. onFulfill
is given the string value "Woohoo!"
. In the .then()
instance method below, the resolve handler function returns this string.
Avoiding Infinite Recursion
A warning here on thenable objects: do not call Promise.resolve()
on a thenable that resolves to itself. This will lead to infinite recursion as the Promise.resolve()
method will continuously attempt to flatten an infinitely-nested Promise
:
Don't do the following!!!
const thenable = { then: (onResolve, onReject) => { onResolve(thenable); },};
Promise.resolve(thenable); // Stop!!! This is bad!! Don't run this code.
From MDN: The Promise.resolve()
method returns a Promise
object that is resolved with a given value. If the value is a Promise
, that Promise
is returned; if the value is a thenable (i.e. has a .then()
method), the returned Promise
will "follow" that thenable, adopting its eventual state; otherwise the returned Promise
will be fulfilled with the value. This function flattens nested layers of Promise
-like objects (e.g. a Promise
that resolves to a Promise
that resolves to something) into a single layer.
See more examples and further documentation here.