实现 Promise 需要完全读懂 Promise A+ 规范,不过从总体的实现上看,有如下几个点需要考虑到:
- then 需要支持链式调用,所以得返回一个新的 Promise;
- 处理异步问题,所以得先用 onResolvedCallbacks 和 onRejectedCallbacks 分别把成功和失败的回调存起来;
- 为了让链式调用正常进行下去,需要判断 onFulfilled 和 onRejected 的类型;
- onFulfilled 和 onRejected 需要被异步调用,这里用 setTimeout 模拟异步;
- 处理 Promise 的 resolve;
class MyPromise {
constructor(executor) {
this.status = 'pending'
this.result = undefined
this.reason = undefined
this.onResolvedArr = []
this.onRejectedArr = []
const resolve = (result) => {
if (this.status === 'pending') {
this.status = 'resolved'
this.result = result
this.onResolvedArr.map(fn => fn())
}
}
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected'
this.reason = reason
this.onRejectedArr.map(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onResolved, onRejected) {
//判断参数类型,一定要为函数
onResolved = typeof onResolved === 'function' ? onResolved : result => result
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw new Error(err)
}
//为了promise的链式调用,返回一个新的promise
const newPromise = new MyPromise((resolve, reject) => {
if (this.status === 'resolved') {
setTimeout(() => { //为了让promise的回调变成异步,加上计时器
try {
const result = onResolved(this.result)
// 为了继续调用resolve,reject 封装一个方法去调用,并且可以继续返回promise
handlePromise(result, newPromise, resolve, reject)
} catch (err) {
reject(err)
}
})
}
if (this.status === 'rejected') {
setTimeout(() => {
try {
const result = onRejected(this.reason)
handlePromise(result, newPromise, resolve, reject)
} catch (err) {
reject(err)
}
})
}
//为了解决promise内存在异步代码,导致then执行时status状态未变更,导致无法执行,做一个发布订阅模式
if (this.status === 'pending') {
this.onResolvedArr.push(() => {
try {
const result = onResolved(this.result)
handlePromise(result, newPromise, resolve, reject)
} catch (err) {
reject(err)
}
})
this.onRejectedArr.push(() => {
try {
const result = onRejected(this.reason)
handlePromise(result, newPromise, resolve, reject)
} catch (err) {
reject(err)
}
})
}
})
return newPromise
}
catch (onRejected) {
return this.then(undefined, onRejected)
}
}
const handlePromise = (result, newPromise, resolve, reject) => {
if (result === newPromise) {
throw new Error('can not return oneself')
}
if (typeof result === 'function' || (typeof result === 'object' && result !== null)) {
let lock = false
try {
const then = result.then
if (typeof then === 'function') {
then.call(result, (r) => {
if (lock) return
handlePromise(r, newPromise, resolve, reject)
lock = true
}, (e) => {
if (lock) return
reject(e)
lock = true
})
} else {
resolve(result)
}
} catch (err) {
reject(err)
}
} else {
resolve(result)
}
}
const test = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('哈哈哈')
}, 1000)
})
test.then((res) => {
console.log(res)
return 11111
}, (err) => {
console.log(err)
}).then(res => {
console.log(res)
})
console.log(111111111111)