I was trying to understand the difference between resolve(thenable)
and resolve('non-thenable-object')
.
In examples below, use promise instead of thenable
because promise is also thenable
and may be easier to understand.
resolve(promise)
let resolvePromise = new Promise(resolve => {
let resolvedPromise = Promise.resolve()
resolve(resolvedPromise)
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
result:
resolve('non-thenable-object')
let resolvePromise = new Promise(resolve => {
resolve('non-thenable-object')
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
result:
So, I checked the spec and found Promise Resolve Functions . Then got to PromiseResolveThenableJob and EnqueueJob.
So, according to the spec, I think demo1 was like
let resolvePromise = new Promise(resolve => {
let resolvedPromise = Promise.resolve()
// resolve(resolvedPromise)
// works like
Promise.resolve().then(() => {
Promise.resolve(resolvedPromise).then(() => {
resolve()
})
})
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
I think so because Promise Resolve Functions says:
- Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob, « promise, resolution, thenAction »).
And PromiseResolveThenableJob says:
This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.
Also, I think demo2 works like
//let resolvePromise = new Promise(resolve => {
//resolve('str')
//})
//works like
let resolvePromise = Promise.resolve('str')
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
As the Promise Resolve Functions says:
If IsCallable(thenAction) is false, then Return FulfillPromise(promise, resolution).
Though the results between Demo1-Demo3 and Demo2-Demo4 are equal, I am still not sure if I was right. So, I am here to ask
whether my logic is right? If not, how do you explain the different orders
between resolve(thenable)
and resolve(non-thenable)
?
Yes, your logic looks right.
new Promise(resolve => resolve('non-thenable-object'))
is equivalent to Promise.resolve('non-thenable-object')
for all purposes.
In your Demo3 I would however recommend to leave out Promise.resolve(resolvedPromise)
. I'm not sure whether that was intentional or not, but Promise.resolve
does have a shortcut when its argument is already a promise, and then returns the resolvedPromise
as-is. You'd rather write
new Promise((resolve, reject) => {
let resolvedPromise = Promise.resolve();
// resolve(resolvedPromise) works like
Promise.resolve().then(() => resolvedPromise.then(resolve, reject));
});
After reading the specification and testing many times I thought I might get it.
Before we start, we have to settle something.
let's call it RESOLVE()
when using resolve
in Promise executor
. For example, RESOLVE(thenable)
means the code like:
new Promise((resolve,reject)=>{
resolve(thenable)
})
while resolve(thenable)
means Promise.resolve(thenable)
Ok, let's begin.
Promise.resolve('non-thenable')
and RESOLVE('non-thenable')
When we are using Promise.resolve('non-thenable')
it comes to Promise.resolve
Then it comes to PromiseResolve
That's the where Promise.resolve('non-thenable')
was transformed to
new Promise(resolve=>{
resolve('non-thenable')
})
So, we have the conclusion:
Promise.resolve('non-thenable')
can be transformed intoRESOLVE('non-thenable')
RESOLVE(thenable)
demo1
let resolveThenable = new Promise((resolve, reject) => {
let thenable = {
then: function (resolve, reject) {
console.log('in thenable')
resolve(42)
}
}
resolve(thenable)
// works like
// Promise.resolve().then(() => {
// thenable.then(resolve)
// })
// should be ?
// Promise.resolve().then(() => {
// thenable.then.[[Value]](resolve)
// })
// equivalent to?
// Promise.resolve().then(() => {
// thenable.then(resolve)
// })
})
resolveThenable.then(() => {
console.log('resolveThenable resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
// 'in thenable'
// 'promise1'
// 'resolveThenable resolved'
// 'promise2'
// 'promise3'
According to Promise Resolve Functions, when we were using RESOLVE(thenable)
it comes to
Then it comes to PromiseResolveThenableJob
This would make RESOLVE(thenable)
works like
Promise.resolve().then(() => {
thenable.then.[[Value]](resolve)
})
So, I thought it is equivalent to
Promise.resolve().then(() => {
thenable.then(resolve)
})
Which got the same result as RESOLVE(thenable)
.
So, we can say
RESOLVE(thenable)
can be transformed to
Promise.resolve().then(() => {
thenable.then(resolve)
})
demo2
let resolvePromise = new Promise((resolve, reject) => {
let resolvedPromise = Promise.resolve()
resolve(resolvedPromise)
// works like
// Promise.resolve().then(() => {
// resolvedPromise.then(() => {
// resolve()
// })
// })
// should be?
// Promise.resolve().then(() => {
// resolvedPromise.then.[[Value]](resolve,reject)
// })
// equivalent to ?
// Promise.resolve().then(() => {
// resolvedPromise.then(resolve)
// })
// equivalent to ?
// Promise.resolve().then(() => {
// resolvedPromise.then(() => {
// resolve()
// })
// })
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
// 'promise1'
// 'promise2'
// 'resolvePromise resolved'
// 'promise3'
When we talked about RESOLVE(resolvedPromise)
, we can find the spec doesn't distinguish thenable
from promise
. So, in the same way, RESOLVE(resolvedPromise)
can be transformed into
Promise.resolve().then(() => {
resolvedPromise.then(resolve)
})
Though, in this case, the order between RESOLVE(thenable)
and RESOLVE(promise)
is different. Because thenable.then
is a sync operation while resolvedPromise.then
is an async operation. They are not the same then
method.
So, here is our conclusion:
Both
RESOLVE(thenable)
andRESOLVE(promise)
can be transformed into
new Promise((resolve, reject) => {
Promise.resolve().then(() => {
thenable.then(resolve)
})
})
It is quite simple when using Promise.resolve(promise)
because it returns promise
argument.
However, things become complicated when using Promise.resolve(thenable)
and the thenable
is not a promise. Let's call it Promise.resolve(nonPromiseThenable)
.
According to Promise.resolve ( x )
Then it comes to
So, Promise.resolve(nonPromiseThenable)
can be transformed to
new Promise(resolve => {
resolve(nonPromiseThenable)
})
And finally comes to
new Promise(resolve => {
Promise.resolve().then(() => {
nonPromiseThenable.then(resolve)
})
})
You can test it in the demo below.
var thenable = {
then(resolve, reject) {
resolve(1)
}
}
// code transformation
Promise.resolve(thenable).then(res => {
console.log(res)
})
// equal
// new Promise(resolve => {
// resolve(thenable)
// }).then(res => {
// console.log(res)
// })
// equal
// new Promise(resolve => {
// Promise.resolve().then(() => {
// thenable.then(resolve)
// })
// }).then(res => {
// console.log(res)
// })
new Promise(resolve => resolve(2))
.then(res => {
console.log(res)
})
.then(res => console.log(3))
In the end, let's make a conclusion:
Promise.resolve('nonThenable')
can be transformed into RESOLVE('nonThenable')
. They have the same effects.Promise.resolve(thenable)
is different from RESOLVE(thenable)
. They have different effects.RESOLVE(thenable)
and RESOLVE(promise)
can be transformed into
new Promise((resolve, reject) => {
Promise.resolve().then(() => {
thenable.then(resolve)
})
})
Promise.resolve(promise) === promise
while Promise.resolve(nonPromiseThenable)
can be transformed into
new Promise(resolve => {
Promise.resolve().then(() => {
nonPromiseThenable.then(resolve)
})
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With