如何利用ES6进行Promise封装总结
原生Promise解析
简介
promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和强大。
promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从语法上来说,Promise是一个对象,从它可以获取异步操作的消息,Promise提供统一的API,各种异步操作都可以用同样的方法进行处理
特点
对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:Pendding、fulfilled、rejected。只有异步操作的结果,可以决定当前是哪一种状态,其他操作都无法改变这个状态。
一旦状态改变,就不会在变,任何时候都可以得到这个结果,只有两种可能:从Pendding变为fulfilled和从Pendding变为rejected。只要这两种情况发生,状态就凝固了,会一直保持这个结果,这时就称为resolved。
利用es6进行Promise封装
处理同步任务
原生方法调用方式
newPromise((resolve,reject)=>{
resolve(1)
}).then(res=>{
console.log(res)//1
})
同步封装思考
1.由调用方式可见Promise是一个类
2.它接收一个回调函数,这个回调函数接受resolve和reject方法作为参数
3.当状态改变后执行then方法,并将resolve或reject的结果作为then方法接受回调函数的参数
classMypromise{
constructor(callback){
this.status='pendding'
//成功结果
this.s_res=null
//失败结果
this.f_res=null
callback((arg)=>{//使用箭头函数this不会丢失
//改变状态为成功
this.status='fulfilled'
this.s_res=arg
},(arg)=>{
//改变状态为失败
this.status='rejected'
this.f_res=arg
})
}
then(onresolve,onreject){
if(this.status==='fulfilled'){//当状态为成功时
onresolve(this.s_res)
}elseif(this.status==='rejected'){//当状态为失败时
onreject(this.f_res)
}
}
}
处理异步任务
原生调用方式
newPromise((resolve,reject)=>{
setTimeOut(()=>{
resolve(1)
},1000)
}).then(res=>{
console.log(res)
})
异步封装思考
1.根据js执行机制,setTimeOut属于宏任务,then回调函数属于微任务,当主线程执行完成后,会从异步队列中取出本次的微任务先执行。
2.也就是说,then方法执行时,状态还没有改变,所有我们需要将then方法执行的回调保存起来,等到异步代码执行完成后,在统一执行then方法的回调函数
classMypromise{
constructor(callback){
this.status='pendding'
//成功结果
this.s_res=null
//失败结果
this.f_res=null
this.query=[]//++
callback((arg)=>{//使用箭头函数this不会丢失
//改变状态为成功
this.status='fulfilled'
this.s_res=arg
//当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.resolve(arg)
})
},(arg)=>{
//改变状态为失败
this.status='rejected'
this.f_res=arg
//当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.reject(arg)
})
})
}
then(onresolve,onreject){
if(this.status==='fulfilled'){//当状态为成功时
onresolve(this.s_res)
}elseif(this.status==='rejected'){//当状态为失败时
onreject(this.f_res)
}else{//++状态没有改变
this.query.push({//保存回调函数到队列中
resolve:onresolve,
reject:onreject
})
}
}
}
处理链式调用
原生调用方式
newPromise((resolve,reject)=>{
resolve(1)
}).then(res=>{
returnres
}).then(res=>{
console.log(res)
})
链式调用思考
原生的Promise对象的then方法,返回的也是一个Promise对象,一个新的Promise才能支持链式调用
下一个then方法可以接受上一个then方法的返回值作为回调函数的参数
主要考虑上一个then方法的返回值:
1.Promise对象/具有then方法的对象
2.其他值
第一个then方法返回一个Promise对象,它的回调函数接受resFn和rejFN两个回调函数作为参数,把成功状态的处理封装为handle函数,接受成功的结果作为参数
在handle函数,根据onresolve返回值的不同做出不同的处理
classMypromise{
constructor(callback){
this.status='pendding'
//成功结果
this.s_res=null
//失败结果
this.f_res=null
this.query=[]//++
callback((arg)=>{//使用箭头函数this不会丢失
//改变状态为成功
this.status='fulfilled'
this.s_res=arg
//当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.resolve(arg)
})
},(arg)=>{
//改变状态为失败
this.status='rejected'
this.f_res=arg
//当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.reject(arg)
})
})
}
then(onresolve,onreject){
returnnewMypromise((resFN,rejFN)=>{
if(this.status==='fulfilled'){//当状态为成功时
handle(this.s_res)
}elseif(this.status==='rejected'){//当状态为失败时
errBack(this.f_res)
}else{//++状态没有改变
this.query.push({//保存回调函数到队列中
resolve:onresolve,
reject:onreject
})
}
functionhandle(value){
//当then方法的onresolve方法有返回值时,保存其返回值,没有使用其保存的值
letreturnVal=onresolveinstanceofFunction&&onresolve(value)||value
//如果onresolve方法返回的是promise对象,则调用其then方法
if(returnVal&&returnVal['then']instanceofFunction){
returnVal.then(res=>{
resFN(res)
},err=>{
rejFN(err)
})
}else{
resFN(returnVal)
}
}
functionerrBack(reason){
if(onrejectinstanceofFunction){
letreturnVal=reject(reason)
if(typeofreturnVal!=='undenfined'&&returnVal['then']instanceofFunction){
returnVal.then(res=>{
resFN(res)
},err=>{
rejFN(err)
})
}else{
resFN(returnVal)
}
}else{
rejFN(reason)
}
}
})
}
}
Promise.all和Promise.race方法
原生调用方式
Promise.all方法接受一个数组,数组中的每一项都是一个Promise实例,只有数组中的所有Promise实例的状态都变为fulfilled时,此时整个状态才会变成fulfilled,此时数组中所有Promise实例的返回值组成一个新的数组,进行传递。
Promise.race方法和Promise.all方法一样,如果不是Promise实例,就会先调用Promise.resolve方法,将参数转为Promise实例,在进行下一步处理。
只要数组中有一个参数的状态变为fulfilled就会进行传递
//将现有对象转换为Promise对象
Mypromise.resolve=(arg)=>{
if(typeofarg=='undefined'||arg==null){//不带有任何参数
returnnewMypromise(resolve=>{
resolve(arg)
})
}elseif(arginstanceofMypromise){//是一个Mypromise实例
returnarg
}elseif(arg['then']instanceofFunction){//具有then方法的对象
returnnewMypromise((resolve,reject)=>{
arg.then(res=>{
resolve(res)
},err=>{
reject(err)
})
})
}else{//参数不是具有then方法的对象,或根本不是对象
returnnewMypromise(resolve=>{
resolve(arg)
})
}
}
Mypromise.all=(arr)=>{
if(!Array.isArray(arr)){
thrownewTypeError('参数必须是一个数组')
}
returnnewMypromise((resolve,reject)=>{
leti=0,result=[]
next()
functonnext(){
//如果不是Mypromise实例需要转换
Mypromise.resolve(arr[i]).then(res=>{
result.push(res)
i++
if(i===arr.length){
resolve(result)
}else{
next()
}
},reject)
}
})
}
Mypromise.race=(arr)=>{
if(!Array.isArray(arr)){
thrownewTypeError('参数必须是一个数组')
}
returnnewMypromise((resolve,reject)=>{
letdone=false
arr.forEach(item=>{
Mypromise.resolve(item).then(res=>{
if(!done){
resolve(res)
done=true
}
},err=>{
if(!done){
reject(res)
done=true
}
})
})
})
}
处理Mypromise状态确定不能改变的特性
在重写callback中的resolve和reject方法执行前,先判断状态是否为'pendding'
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。