初始化结构
此时先新建一个class类,因为原生promise需要new一个实例,所以我们需要类和构造函数 PS:我常常忘记解释,但我会尽量注释,写此篇时默认你了解同步异步js运行机制和promise机制 (关于js同步异步可以见这篇) 微任务/宏任务和同步/异步之间的关系
class Pro {
// promise的三种状态
static PENDING = "待定";
static fulfilled = "成功";
static rejected = "拒绝";
constructor(fn) {
// 构造函数接收一个函数并执行(同步)
// 初始化一个状态
this.status = pro.PENDING
// 结果
this.result = null
fn(this.resolve., this.reject)
}
resolve(res) {
// 如果状态为待定则赋值成功
if (this.status === pro.PENDING) {
this.status = pro.fulfilled
// 赋值结果
this.result = res
}
}
// 和resolve类似暂时放空
reject() {
}
// .then回调
then(onFulfilled, onRejected) {
// 两个函数参数分别对应resolve,reject,且同时只能有一个
if (this.status === pro.fulfilled) {
// resolve 执行并返回结果
onFulfilled(this.result)
}
// 和resovle对应,暂时放空
if (this.status === pro.rejected) {
// reject 执行并返回结果
onRejected(this.result)
}
}
}
实例化测试一下先
操作和原生promise类似
console.log(1);
let pro = new Pro((resolve, reject) => {
resolve('myPro')
console.log(2);
})
pro.then(
(res) => {
console.log(res);
},
(rejRes) => {
console.log(rejRes);
},
)
console.log(3);
果然报错,看看是啥问题
原来是resolve里的this指向问题,没有指到实例上,打印出来是undefined,所以这里我用bing(this)给他指路指到实例上
fn(this.resolve.bind(this), this.reject.bind(this))
再打印,这时可以了,但执行顺序不对,没有进行异步,正确的应该是1 2 3 mypro,因为then是异步
在执行then时加个定时器完成异步
if (this.status === Pro.fulfilled) {
// resolve 执行并返回结果
// 定时器进行异步
setTimeout(() => {
onFulfilled(this.result)
})
}
这时再完善,在实例化函数里加个定时器
console.log(1);
let pro = new Pro((resolve, reject) => {
console.log(2);
// 加个定时器查看当resolve函数也成异步时,then会怎么执行
setTimeout(() => {
resolve('myPro')
console.log(4);
})
})
pro.then(
(res) => {
console.log(res);
},
(rejRes) => {
console.log(rejRes);
},
)
console.log(3);
执行
发现没有输出 myPro 推测是then没有执行,而then里是通过if判断状态是否执行函数参数onFulfilled,于是在then和定时器里分别打印状态
// .then回调
then(onFulfilled, onRejected) {
console.log(1,this.status);
// 两个函数参数分别对应resolve,reject,且同时只能有一个
if (this.status === Pro.fulfilled) {
let pro = new Pro((resolve, reject) => {
console.log(2);
// 加个定时器查看当resolve函数也成异步时,then会怎么执行
setTimeout(() => {
console.log(2,pro.status);
resolve('myPro')
console.log(3,pro.status);
console.log(4);
})
})
结果如下
可以发现then执行判断状态时,实例的resolve还没执行所以状态为待定,而我此时then里没有对状态为待定时进行处理,由于resolve处于异步队列还未执行,所以我先将then函数参数onFulfilled暂存在数组里,等待resolve函数触发时再取出来循环执行
// 保留then里的函数,保证其在状态改变时能执行
this.resolveArr = []
this.rejectArr = []
fn(this.resolve.bind(this), this.reject.bind(this))
// 当状态为待定时
if (this.status === Pro.PENDING) {
this.resolveArr.push(onFulfilled)
this.rejectArr.push(onRejected)
}
再次执行
此时发现虽然resolve执行了,但是执行的顺序不对,应该为异步执行,即排在 4 后执行 所以我在resolve里最外层再加个定时器进入异步队列
resolve(res) {
// 异步执行
setTimeout(() => {
// 如果状态为待定则赋值成功
if (this.status === Pro.PENDING) {
this.status = Pro.fulfilled
// 赋值结果
this.result = res
// 如果数组有暂存的then函数,循环执行
this.resolveArr.forEach(cb => {
cb(res)
})
}
})
}
执行,这次顺序对了
promise的链式调用
先测试
pro.then(
(res) => {
console.log(res);
},
(rejRes) => {
console.log(rejRes);
},
).then(
(res) => {
console.log(res);
},
(rejRes) => {
console.log(rejRes);
},
)
果然报错,原因是.then的对象得是个promise实例,所以我们在.then函数调用后返回一个新的promise实例供下个then调用
// .then回调
then(onFulfilled, onRejected) {
// 供下个then链式调用
return new Pro((resolve, reject) => {
// 当状态为待定时
if (this.status === Pro.PENDING) {
this.resolveArr.push(onFulfilled)
this.rejectArr.push(onRejected)
}
// 两个函数参数分别对应resolve,reject,且同时只能有一个
if (this.status === Pro.fulfilled) {
// resolve 执行并返回结果
// 定时器进行异步
setTimeout(() => {
onFulfilled(this.result)
})
}
// 和resovle对应,暂时放空
if (this.status === Pro.rejected) {
// reject 执行并返回结果
onRejected(this.result)
}
})
}
执行没报错,成功!
今天暂时就写到这,这个小仿写还有很多bug和没做的东西,后续继续添加和完善
作者:徐煜&煎包