借由queueMicrotask实现promise
之前那篇的基础上改进
function Promise(fn) {
let that = this
this.resolvedCb = []
this.rejectedCb = []
this.state = 'pending'
let resolve = function (value) {
if (value instanceof Promise) { //解决resolve包裹promise的问题
value.then(resolve, reject)
} else {
queueMicrotask(() => {
if (that.state === 'pending') {
that.state = 'resolved'
that.resolvedCb.forEach(cb => cb(value))
}
})
}
}
let reject = function (reason) {
queueMicrotask(() => {
if (that.state === 'pending') {
that.state = 'rejected'
that.rejectedCb.forEach(cb => cb(reason))
}
})
}
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
//解决透传的问题
onFulfilled = onFulfilled instanceof Function ? onFulfilled : r => r
onRejected = onRejected instanceof Function ? onRejected : r => {
throw r
}
return new Promise((resolve, reject) => {
this.resolvedCb.push(function (value) {
try {
resolve(onFulfilled(value))
} catch (e) {
reject(e)
}
})
this.rejectedCb.push(function (reason) {
try {
resolve(onRejected(reason))
} catch (e) {
reject(e)
}
})
})
}
-
事件循环执行到微任务时,会把微任务放入微任务队列,待到执行栈代码执行完毕之后才会执行微软栈中的内容;因此使用了html的微任务api
queueMicrotask
将resolve和reject的回调函数放入微任务队列。 -
之前代码then中的FULFILLED和REJECTED状态部分是同步执行的现在不需要了
-
之前漏考虑了
new Promise((resolve)=>{resolve(1)}).then().then((res) => console.log(res))
这种透传的问题,现在修正了 -
之前是在then中解决resolve包裹promise的问题,现在同步执行到then时是得不到value的内容的,因此将处理这个问题的代码放到了resolve中
-
参考资料
- https://blog.csdn.net/boringsummers/article/details/89140702
- https://promisesaplus.com/#notes
- https://www.jianshu.com/p/43de678e918a