前言
Promise的then方法如果返回一个数值,会在链式then的下一次回调中打印出来,除此之外,如果then方法返回一个promise则会在下一个then中返回上一个返回的promise的执行结果,这次慢慢来实现,符合promiseA+规范的
function resolvePromise(x, promise2, resolve, reject) {
//解决循环引用问题
if (x === promise2) {
return reject(new TypeError("循环引用"));
}
//如果promise2是一个函数或者对象
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let called
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, function (y) {
if (called) return
called = true
//这里的y也有可能是一个promise,所以继续解析
resolvePromise(y, promise2, resolve, reject)
}, function (r) {
if (called) return
called = true
reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
// 普通值
resolve(x)
}
}
class Promise {
constructor(executor) {
this.state = 'PENDING'
this.onFulfilledCB = []
this.onRejectedCB = []
this.value = ''
this.reason = ''
try {
executor(resolve.bind(this), reject.bind(this))
} catch (error) {
reject(error)
}
function resolve(value) {
if (this.state === 'PENDING') {
this.state = 'FULFILLED'
this.value = value
this.onFulfilledCB.forEach(fn => fn())
}
}
function reject(reason) {
if (this.state === 'PENDING') {
this.state = 'REJECTED'
this.reason = reason
this.onRejectedCB.forEach(fn => fn())
}
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : r => r
onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e }
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'FULFILLED') {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
}
if (this.state === 'REJECTED') {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
}
if (this.state === 'PENDING') {
this.onFulfilledCB.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
this.onRejectedCB.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (error) {
reject(error)
}
}, 0);
})
}
})
return promise2
}
catch(err) {
this.then(null, err)
}
}