「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」。
传送门
从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现 从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么 从零手撕Promise,掌握Promise的实现原理(4)之then方法链式调用的初步实现 从零手撕Promise,掌握Promise的实现原理(5)之then方法链式调用的进阶实现
回顾
经过上一篇文章的介绍我们的promise现在已经长这样了
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const resolvePromise = (promise, x, resolve, reject) => {
}
class Promise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = undefined
//存放onFulfilled
this.onResolvedCallbacks = []
//存放onRejected
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === PENDING) {
this.value = value
this.state = FULFILLED
//promise实例状态改变后调用暂存的onFulfilled
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === PENDING) {
this.reason = reason
this.state = REJECTED
//promise实例状态改变后调用的onRejected
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
//executor函数执行过程中出错,将会导致Promise失败
executor(resolve,reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected){
let promise = new Promise((resolve, reject) => {
switch(this.state){
case FULFILLED:
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
break
case REJECTED:
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
break
default:
this.onResolvedCallbacks.push(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
this.onRejectedCallbacks.push(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
}
})
return promise
}
}
为什么then方法中的回调(onFulfilled、onRejected)是微任务?
- 像上面图片展示的那样,当代码执行到
resolvePromise的时候其实我们是拿不到promise(序号2)的,这样去访问控制台会报错。
这个错误的意思是说,初始化前无法访问
promise,因为对于Promise(序号2)来说,此时Promise(序号2)还处于自身ecexutor函数执行的时候,还没有初始化完成,也就是说此时还不存在这个实例。那么我们后续在resolvePromise函数中是无法拿到promise(序号2)的。
- 这也是为什么then方法中的回调(onFulfilled、onRejected)是异步微任务,我们可以通过浏览器提供的
queueMicrotask方法去创建一个异步微任务,但是这个方法的兼容性不是很好,我们也可以用setTimeout异步宏任务去替代它,那么我们的then方法改造如下:
then(onFulfilled, onRejected){
let promise = new Promise((resolve, reject) => {
switch(this.state){
case FULFILLED:
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
case REJECTED:
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
default:
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
}
})
return promise
}
- 经过这番改造后,我们在
resolvePromise函数中就可以拿到promise进行接下来的操作了
那么我们的Promise现在变成了这样
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const resolvePromise = (promise, x, resolve, reject) => {
}
class Promise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = undefined
//存放onFulfilled
this.onResolvedCallbacks = []
//存放onRejected
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === PENDING) {
this.value = value
this.state = FULFILLED
//promise实例状态改变后调用暂存的onFulfilled
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === PENDING) {
this.reason = reason
this.state = REJECTED
//promise实例状态改变后调用的onRejected
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
//executor函数执行过程中出错,将会导致Promise失败
executor(resolve,reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected){
let promise = new Promise((resolve, reject) => {
switch(this.state){
case FULFILLED:
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
case REJECTED:
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
default:
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
}
})
return promise
}
}
下篇文章继续完成相关内容
传送门
从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现 从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么 从零手撕Promise,掌握Promise的实现原理(4)之then方法链式调用的初步实现 从零手撕Promise,掌握Promise的实现原理(5)之then方法链式调用的进阶实现