Promise实现原理
我们都知道,new一个Promise时,需要传递一个函数exectF,函数一般以两个修改状态函数作为参数,第一个函数是来将pending状态修改成成功状态,第二个函数是来将pending状态修改成失败状态,只有状态发送变化,promise的then函数才会执行。创建实例时,将promise的resolve和reject传给exectF,立即执行该函数,函数内部若执行了参数方法,则会执行对应的resolve方法或reject方法,从而修改promise的状态,
class _Promise{
constructor(exectF){
this.status='pending'//初始状态
this.value=undefined//传递给then函数的参数
this.resolveQueue=[]
this.rejectQueue=[]
//判断是否传入了一个函数,否则执行会出错
typeof exectF==='function'&&
exectF(resolve.bind(this),reject.bind(this))
function resolve(result){
//模拟promise的异步调用then方法
if(this.status==='pending'){
this.status='fulfilled'
this.value=result
this.resolveQueue.forEach((fn)=>{
fn()
})
}
}
function reject(result){
if(this.status==='pending'){
this.status='rejected'
this.value=result
this.rejectQueue.forEach((fn)=>{
fn()
})
}
}
}
/*因为js是从上到下执行的,then函数属于异步任务(在此处采用setTimeout模拟),
所以若遇到then函数时,该promise对象状态为pending,将当前的then操作存入队列,状态变化后再执行
(比如执行函数存在定时器,且在定时器回调函数执行resolve或reject函数,定时器属于异步代码,
遇到then方法时,resolve或reject方法还未执行,只有定时器的回调函数执行后promise对象的状态才会变化)
*/
then(fn1,fn2){
var result,pre=this
if(this.status==='pending'){
/*因为then返回新promise对象,且影响新对象的状态,
所以在执行then操作时,更改下一个promise对象的状态
*/
return new _Promise((resolve,reject)=>{
/*状态变化时,执行当前对象状态对应的队列中的回调函数,
并更改下一个promise对象的状态
*/
pre.resolveQueue.push(()=>{
try{
result=fn1(pre.value)
/*如果回调函数返回一个promise对象,
则将promise的返回值传给下一个promise
*/
if(result instanceof _Promise){
result.then(resolve,reject)
}
else resolve(result)
}catch(e){
reject(e)
}
})
pre.rejectQueue.push(()=>{
try{
result=fn2(pre.value)
if(result instanceof _Promise){
result.then(resolve,reject)
}
else resolve(result)
}catch(e){
reject(e)
}
})
})
}
/*当状态为成功或失败时,无论是fulfill还是rejected状态的执行函数,
若无设置返回promise对象,则默认返回成功状态的promise对象,
传入参数为执行函数的返回值
*/
else{
return new _Promise((resolve,reject)=>{
//模拟异步调用
setTimeout(()=>{
try{
if(pre.status==='fulfilled'){
result=fn1(pre.value)
}
else result=fn2(pre.value)
if(result instanceof _Promise){
result.then(resolve,reject)
}
else resolve(result)
}catch(e){
reject(e)
}
})
})
}
}
catch(fn){
return this.then(undefined,fn)
}
finally(fn){
return this.then((resolve)=>{
_Promise.resolve(fn()).then(()=>resolve)
},(reject)=>{
_Promise.resolve(fn()).then(()=>{throw reject})
})
}
}
_Promise.resolve=function(result){
return new _Promise(resolve=>resolve(result))
}
_Promise.reject=function(result){
return new _Promise((undefined,reject)=>reject(result))
}
使用Promise简单实现Promise.all
Promise.all()将多个 Promise 实例包装成一个新的 Promise 实例。新的Promise的状态由所有promise实例状态决定,只有所有的promise的状态都变成fulfilled,新的promise的状态才会变成fulfilled。而只要有一个promise是rejected,新promise的状态就变成rejected
//前提条件是输入数组,且元素均为promise实例
function all(arr){
var values=[],n=arr.length
return new Promise((resolve,reject)=>{
arr.forEach((promise,index)=>{
promise.then((value)=>{
values.push(value)
if(index===n-1){
resolve(values)
}
},(e)=>reject(e))
})
})
}
/*优化,使用Promise.resolve,因为Promise.all()
方法接受一个数组作为参数,数组元素都是 Promise 实例,
如果不是,就会先调用Promise.resolve方法,将参数转为 Promise实例。
*/
function all(arr){
var values=[],n=arr.length
return new Promise((resolve,reject)=>{
arr.forEach((promise,index)=>{
Promise.resolve(promise).then((value)=>{
values.push(value)
if(index===n-1){
resolve(values)
}
},(e)=>reject(e))
})
})
}
使用Promise实现Promise.race
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。只要所有promise实例中有一个实例先改变状态,就会改变新promise的状态。那个率先改变的 Promise 实例的返回值,就传递给新promise的回调函数。Promise.race()方法的参数与Promise.all()方法一样,如果不是Promise实例,就会先调用Promise.resolve()方法,将参数转为 Promise 实例
function race(arr){
var n=arr.length
return new Promise((resolve,reject)=>{
arr.forEach((promise,index)=>{
Promise.resolve(promise).then((value)=>{
resolve(value)
},(e)=>reject(e))
})
})
}
之前就已经手动实现过,今天整理发现有许多遗漏的细节,所以又花了点时间完善,测试过多组数据都可以,不过可能还有缺陷,所以如果有问题,欢迎指出~还有一些Promise方法还没实现,之后会一一补上
参考 1.《ECMAScript 6 入门教程》阮一峰 2.blog.csdn.net/weixin_4473…