const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.result = undefined
this.fulfillReactions = []
this.rejectReactions = []
const that = this
function resolve(value) {
if (that.status !== PENDING) {
return
}
if (that === value) {
const selfResolutionError = new TypeError('Cannot resolve to self.')
return reject(selfResolutionError)
}
if (typeof value === 'object' && typeof value.then === 'function') {
value.then(resolve, reject)
} else {
that.status = FULFILLED
that.result = value
triggerReactions(that, 'fulfillReactions')
}
}
function reject(value) {
if (that.status !== PENDING) {
return
}
that.status = REJECTED
that.result = value
triggerReactions(that, 'rejectReactions')
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
const C = this.constructor
const promiseCapability = new PromiseCapability(C)
return performThen(this, onFulfilled, onRejected, promiseCapability)
}
catch(onRejected) {
return this.then(null, onRejected)
}
static resolve(value) {
if (value instanceof this) {
return value
}
return new MyPromise(function(resolve) {
resolve(value)
})
}
static reject(value) {
return new MyPromise(function(resolve, reject) {
reject(value)
})
}
}
function performThen(promise, onFulfilled, onRejected, resultCapability) {
function createJob(job, value) {
if (typeof job === 'function') {
return job(value)
} else {
return value
}
}
const fulfillReaction = value => {
const result = createJob(onFulfilled, value)
if (typeof result === 'object' && typeof result.then === 'function') {
result.then(value => {
resultCapability.resolve(value)
})
} else {
resultCapability.resolve(result)
}
}
const rejectReaction = value => {
const result = createJob(onRejected, value)
if (typeof onRejected === 'function') {
resultCapability.resolve(result)
} else {
resultCapability.reject(result)
}
}
switch (promise['status']) {
case 'pending':
promise.fulfillReactions.push(fulfillReaction)
promise.rejectReactions.push(rejectReaction)
break
case 'fulfilled':
triggerReaction(fulfillReaction, promise.result)
break
case 'rejected':
triggerReaction(rejectReaction, promise.result)
break
}
return resultCapability.promise
}
function triggerReactions(promise, type) {
promise[type].forEach(reaction => {
triggerReaction(reaction, promise.result)
})
}
function triggerReaction(reaction, result) {
setTimeout(() => {
reaction(result)
})
}
class PromiseCapability {
constructor(C) {
this.promise = new C((resolve, reject) => {
this.resolve = resolve
this.reject = reject
})
}
}
MyPromise.all = function(promises) {
const promiseCapability = new PromiseCapability(this)
const result = []
let num = promises.length
promises.forEach((promise, index) => {
result[index] = undefined
MyPromise.resolve(promise).then(value => {
result[index] = value
num -= 1
if (num === 0) {
promiseCapability.resolve(result)
}
})
}, promiseCapability.reject)
return promiseCapability.promise
}
MyPromise.race = function(promises) {
const promiseCapability = new PromiseCapability(this)
promises.forEach(promise => {
MyPromise.resolve(promise).then(
promiseCapability.resolve,
promiseCapability.reject
)
})
return promiseCapability.promise
}
module.exports = MyPromise
复制代码