Inspect what happens if these things are passed to Promise.resolve

Real promise constructed with new Promise constructor

1
2
3
4
5
6
7
8
9
const p1 = new Promise((resolve, reject) => {
resolve(3)
reject(
(() => {
console.log('hi')
return 4
})()
)
})

p1 will be a fulfilled promise with value 3. reject will be executed by the constructor, but it will not modify the promise because the promise is already resolved.

Promise.resolve(p1) is the same as p1.

1
2
> Promise.resolve(p1) === p1
true

Real promise constructed with new Promise constructor but throws inside the fulfill callback

1
2
3
4
5
6
7
const p2 = new Promise((resolve, reject) => {
resolve(
(() => {
throw new Error('hi')
})()
)
})

p2 will be in the rejected state, the rejection reason is Error: hi.

1
2
> Promise.resolve(p2) === p2
true

Thenable object

1
2
3
4
5
6
7
8
9
10
11
const p3 = {
then: (resolve, reject) => {
resolve(3)
reject(
(() => {
console.log('hi')
return 4
})()
)
},
}

Here what Promise.resolve does is equivalent to:

1
2
3
new Promise((resolve, reject) => {
p3.then(resolve, reject)
})

The reject part will still be executed, but the result is a proper Promise that only has one immutable fulfilled status with the value 3.
By contrast, if we use p3 as a promise and let is participate in a promise chain, there will be silly behaviours, i.e. both onFulfilled and onRejected will be called.

Nested thenable object

1
2
3
4
5
const p4 = {
then: (resolve) => {
resolve({then: (resolve) => resolve(3)})
},
}

Here what Promise.resolve(p4) does is equivalent to unpackThen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function unpackThen(thenable) {
return new Promise((resolve, reject) => {
thenable.then(resolve, reject)
}).then(result => {
if(isThenable(result)) {
return unpackThen(result)
}
return result
})
}

function isThenable(v) {
return v !== null &&
(
typeof v === "object" ||
typeof v === "function"
) &&
typeof v.then === "function"
}

Use Promise.resolve to implement Promise.first

Requirement: ignore rejections and return a promise that resolves to the first fulfillment value among the promises; if all promises reject, reject the promise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(!Promise.first){
Promise.first = function(prs) {
return new Promise((resolve, reject) => {
let rejectCount = 0
prs.forEach(pr => {
Promise.resolve(pr).then(
function onFulfilled(v){resolve(v)},
function onRejected(){
rejectCount++
if(rejectCount === prs.length) {
reject('All promises rejected!')
}
})
})
})
}
}