我们对于掌握promise的写法有好多种,就和业务的实现方式是一样的,当然每个人对于这个东西的理解也有所不同。但只要你是对的,符合promiseA+规范,相信别人是可以看懂的。写promise源码很重要的一点是要有全局观,大局观。这个是什么意思呢,分享一个我自己的故事,我接触promise源码已经有好长时间了,从最初简单的农村promise源码的实现,到现在城市promise的实现,其实我个人的观点有很大的改变,所以我会尽量模仿别人写的那种,忘掉我原来自己看到或者学到的promise.这也是我分享promise的一个原因。
<script>
const PENDDING = 'pendding'
const REJECTED = 'rejected'
const RESOLVED = 'resolved'
class myPromise{
constructor(handle){
this.status = PENDDING
this.value = undefined
this.reason = undefined
this.resolveCallback = []
this.rejectCallback = []
let resolve = (val)=>{
if(this.status == PENDDING){
this.status = RESOLVED
this.value = val
this.resolveCallback.forEach(fn=>fn())
}
}
let reject = (error)=>{
if(this.status == PENDDING){
this.status = REJECTED
this.reason = error
this.rejectCallback.forEach(fn=>fn())
}
}
try{
handle(resolve,reject)
}catch(error){
reject(error)
}
}
then(onResolve,onReject){
if(this.status == RESOLVED){
onResolve(this.value)
}
if(this.status == REJECTED){
onReject(this.reason)
}
if(this.status == PENDDING){
this.resolveCallback.push(()=>{onReject(this.value)})
this.rejectCallback.push(()=>{onReject(this.reason)})
}
}
}
const p = new myPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(111)
},0)
}).then((res)=>{
console.log(res)
},(err)=>{
console.log(err)
})
</script>
老铁们不要着急,上来就粘代码?什么烂博客?哈哈,
我说一下这个的运用场景。他支持你正常的promise里面有异步。then可以使用,报错可以捕获。仅仅而已,不支持链式调用。
解释一下,then里面三种场景:他把所有的情况都考虑进去了,pendding,resolve,reject.一开始看到这种分类写法我就被他吸引了,如果你自己写过简单的promise,我相信你也会被这个分类写法吸引。
这里面用到是简单的发布订阅模式。(与观察者模式有一点点区别,我的上一篇博客就是观察者模式)
这里面的精髓就是如何知道promise里面是异步还是同步,
那么大家知道如果是异步他会先去执行then函数,那么可想此时的status == PENDDING
也就是我们then,then里面有两个参数,一个成功的回调,一个失败的回调,
我们不管他是成功的回调,还是失败的回调,只要他执行then函数,我们就把我们事先准备好的两个数组里面push东西,终于
this.resolveCallback.push(()=>{onReject(this.value)}) ------------>把我们成功的回调包装成一个函数,放进一个数组
this.rejectCallback.push(()=>{onReject(this.reason)}) ------------>把我们失败的回调包装成一个函数,放进一个数组
执行完这两条代码后,发现我们有宏任务,开始执行异步代码。当异步结束后,resolve(111)这是status变为了RESOLVED,遍历resolveCallback这个数组,这个数组中的第一项就是一个函数,执行后也就是我们成功的回调执行了,OH YEAR
promise里面有异步我们就实现了
我们想想当promise里面是同步的时候,我们直接resolve(111),status直接变为RESOLVED,执行then的时候我们发现他的status是RESOLVED,我们直接走成功的回调就ok了
下面来看下promise.finally的实现:
由第一个promise.resovle那个例子知道resolve的data最后还通过then返回,可想到
Promise.resolve(callback()).then(()=>data)
由第二个promise.reject那个例子知道里面必然是 throw err 了,而且还可以通过then返回,可想到
Promise.resolve(callback()).then(()=>{throw err})
一起来看下真正的写法:
Promise.finally = function(callback){
return this.then(data=>{
return Promise.resolve(callback()).then(()=>data)
},err=>{
return Promise.resolve(callback()).then(()=>{throw err})
})
}
callback是个普通值或者promise ,Promise.resolve的作用:包裹成promise
静态方法resolve ,reject ,race
resolve :两种情况一种参数是promise,另一种不是。如果是promise
Promise.resolve(111)
Promise.resolve(new Promise((resolve)=>{resolve(1111)}))
可想到
static resolve(value){
if(value instanceof Promise){
return value
}else{
return new Promise((resolve,reject)=>resolve(value))
}
}
Promise.reject(123)
static reject(value){
return new Promise((resolve,reject)=>reject(value))
}
这两个是不是很简单啊,哈哈
再看下race的实现,简单说下这个api,这个race方法参数是数组,返回最快的那个返回的结果,因为数组中的参数有可能是promise也有可能不是promise,不过返回的总是最快的那个
static race(list){
return new Promise((resolve,reject)=>{
for(let k of list){
this.resolve(list[k]).then(data=>{
resolve(data)
},err=>{
reject(err)
})
}
})
}