关于promise经常用到,用来处理异步请求,也经常刷到一些什么手写promise等等,我一般对此没有太大的兴趣,今天忽然又看到这个话题,想着来试试?
1、日常使用方法如下
let p = new Promise((resolve, rejected) => {
setTimeout(() => {
resolve('真的Promise')
},3000);
})
p.then((res)=>{
console.log(res,'结果')
})
可以发现
1、使用时是 new xxx,可以知道promise原理是一个构造类
2、接收一个函数,且有两个参数,两个参数也为函数
3、实例有一个.then方法,且也包含两个函数,res,err
2、基于上述,我们可以先大概构思如下
class MyPromise {
constructor(executor) {
//绑定this
executor(this._resolve.bind(this), this._rejected.bind(this))
}
//成功执行函数
_resolve(res) { }
_rejected(err) { }
//结果回调
_then(resCb,errCb) { }
_catch(err) {
}
}
有了这个类,我们大概可以得到一个简易版的 Promise,如下
function get() {
return new MyPromise((resolve, rejected) => {
setTimeout(() => {
resolve('2秒后执行')
}, 2000)
})
}
get()._then((res) => {
console.log(res, '_then------结果')
})
测试发现,我们并不能得到什么,原因在于 尽管我们定义的方法都有,但我们并没有把 最重要的 resolve的值,传给 _then 中的回调函数,所以我们的_then中什么也得不得
3、改进
class MyPromise {
//内部定义三种状态
static pending = 'pending'
static fulfilled = 'fulfilled'
static rejected = 'rejected'
constructor(executor) {
//初始化
this.status = MyPromise.pending
this.value = null
this.rejectValue = null
//保存 .then中传递的两个回调
this.queue = []
executor(this._resolve.bind(this), this._rejected.bind(this))
}
_resolve(res) {
//进入这个函数时,代表成功,这个时候
//我们要执行.then中成功的回调函数
//因此在.then执行初期,就将两个回调用数组缓存起来
//等resolve执行时,在执行这个回调
this.status = MyPromise.fulfilled
this.value = res
this.queue.forEach((item,index)=>{
item.resCb(this.value)
})
}
_rejected(err) { }
_then(resCb,errCb) {
this.queue.push({
resCb,
errCb
})
}
_catch(err) {}
}
4、总结
整个过程可以理解为,promise 成功时,会执行 resolve( res ),那么在我们要在.then( (res) =>{} ) 中得这个结果,最好的方式就是成功resolve后,再执行then中的回调,将结果传递出去,所以这个采用了现将 then中的回调缓存起来,resolve后再执行它,这其实也叫订阅者模式,结合使用方法,再次理解
function get() {
return new MyPromise((resolve, rejected) => {
setTimeout(() => {
// resolve 函数执行,传递结果
resolve('2秒后执行')
}, 2000)
})
}
//_then要想得到 resolve 的结果,相当于如下操作,
//resolve函数内部再执行一次 _then中的回调,将结果传出去
/*
resolve( res ){
//resCb 为_then()中的 回调函数 res
resCb(res)
}
*/
get()._then((res) => {
console.log(res, '_then------结果')
})
主要理解 .then中res的函数,其实是在resolve内部以回调的方式执行的