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