手写Promise

目录

前言

状态

使用方法

构造函数

对象

结论

第一阶段

搭建基本结构

思路

代码实现

测试一下

实现then方法获取异步值

思路

改造代码如下

测试一下

成功场景

 失败场景

实现类的resolve,reject以及catch方法

思路

代码实现

测试一下

第一阶段总结

第二阶段

try catch错误处理机制

思路

代码实现

测试一下

then方法完善

思路

代码实现(全部代码)

测试一下

异步值是promise

异步值是普通值

链式调用

总结

第三阶段

完善类的resolve和reject

思路

代码实现

测试一下

实现all方法

思路

代码实现

测试一下

总结

心得体会

附上全部代码


前言

promise对于前端的重要性是毋庸置疑的,自己也在之前写过一篇promise的使用:

promise的使用和实例方法-CSDN博客

首先思考一个问题:promise的关键要素有什么?

这里我认为有两个关键点:1.promise的状态2.promise的使用方法

状态

promise的状态有三个:pending,fulfilled,rejected

而且只能由pending转化为其他两个,并且转化之后就无法在变化

使用方法

promise有两种使用方法:构造函数和对象

构造函数

将promise当做构造函数使用,让实例对象调用then,catch,finally等方法去获取异步值

let pro =  new myPromise((resolve,reject)=>{setTimeout(()=>{resolve('王惊涛')// reject('失败了')},1000)pro.then(res=>{console.log(res,'成功的值')
},rej=>{console.log(rej,'失败的值')
})
pro.catch(err=>{console.log(err,'错误的原因')
})
对象

对象直接可以调用resolve,reject,all,race等方法

Promise.resolve('王惊涛').then(res=>{console.log(res,'成功的值')
})

结论

Promise既可以作为函数,也可以作为对象,所以我们需要创建的是一个函数对象。

准确的说:一个用于静态方法和属性的构造函数

第一阶段

搭建基本结构

思路

1.创建一个构造函数或者类,这里我就直接用class类了

2.类里面有一个status属性,用来表示Promise的状态,成功和失败都会改变pending状态,并且不会再发生变化

3.promise作为构造函数,接受的参数是一个函数,所以:constructor接受一个函数。并且这个函数的两个参数也都是函数:resolve和reject方法,用来调用成功或者失败的值(这里为了区分,我就是用resolveFun和rejectFun)

4.new Promise的实例对象可以使用then和catch方法对异步值进行成功或者失败的操作

5.成功和失败都是需要回调函数去操作的,所以需要集合保存回调函数

6.promise本身作为对象可以调用resolve,reject,all等方法,这里需要设置静态方法,可以让类直接使用

代码实现

class myPromise{//new myPromise((res,rej)=>{res('成功')})//new myPromise((res,rej)=>{rej('失败')})constructor(proFun){  //这里的proFun就是:(res,rej)=>{res('成功')proFun(this.resolveFun,this.rejectFun) }status = 'pengding' //状态resolveValue = null  //成功的值rejectReason = null  //失败的值successCallBackList = []  //成功回调集合failCallBackList = []   //失败回调集合//resolve处理函数resolveFun = (value)=>{console.log(value,'成功的值')this.status = 'fulfilled'  //改变状态为成功this.resolveValue = value  //赋值成功值}//reject处理函数rejectFun = (reason)=>{console.log(reason,'失败的值')this.status = 'rejected'  //改变状态为成功this.rejectReason = reason  //赋值成功值}//then实例方法thenFun = ()=>{console.log('测试then方法是否可以使用')}//catch实例方法catchFun = ()=>{}//promise直接调用resolve方法:myPromise.resolve('成功')static resolve = ()=>{console.log('测试resolve对象方法是否可用')}//promise直接调用reject方法:myPromise.reject('失败')static reject = ()=>{}//promise直接调用all方法:myPromise.all[pro1,pro2]static all = ()=>{}
}

测试一下

        //测试let pro = new myPromise(res => {setTimeout(() => {res('成功')}, 1000)})pro.thenFun(res => {})myPromise.resolve('成功')

实现then方法获取异步值

then方法无疑是promise核心的代码,因为then里面封装的是获取异步之后的回调逻辑。

我们在调用了resolveFun之后,会改变状态,并且把给value赋值,然后最关键的就是需要调用then方法中定义的函数

思路

1.then方法接收两个参数,并且这两个参数都是函数,一个用来处理成功后的逻辑,一个用来处理失败后的逻辑

2.两个函数的参数分别对应resolveValue和rejectReason的结果值

3.这个时候我们就应该将成功和失败的回调函数作为参数保存到我们在类中定义successCallback和failCallback这两个数组中

4.然后调用数组中的回调函数,并且将value值作为thenFun中的函数参数,然后就可以在then调用之后,获取到异步的值了

改造代码如下

只修改这个三个方法.其余代码不变

            //resolve处理函数resolveFun = (value) => {console.log(value, '成功的值')this.status = 'fulfilled'  //改变状态为成功this.resolveValue = value  //赋值成功值console.log(this.successCallBackList, '成功的回调函数列表')this.successCallBackList[0](value)}//reject处理函数rejectFun = (reason) => {console.log(reason, '失败的值')this.status = 'rejected'  //改变状态为成功this.rejectReason = reason  //赋值成功值console.log(this.failCallBackList, '失败的回调函数列表')this.failCallBackList[0](reason)}//then实例方法thenFun = (resolveCallBack, rejectCallBack) => {// console.log('测试then方法是否可以使用')this.successCallBackList.push(resolveCallBack)this.failCallBackList.push(rejectCallBack)}

测试一下

成功场景
        //测试let pro = new myPromise((res, rej) => {setTimeout(() => {res('成功')// rej('失败')}, 1000)})pro.thenFun(res => {console.log(res, '成功后的操作逻辑')}, rej => {console.log(rej, '失败后的操作逻辑')})

 失败场景
        //测试let pro = new myPromise((res, rej) => {setTimeout(() => {// res('成功')rej('失败')}, 1000)})pro.thenFun(res => {console.log(res, '成功后的操作逻辑')}, rej => {console.log(rej, '失败后的操作逻辑')})

归纳一下这里究竟发生了什么,就用上面的失败为例:

1.定义一个pro变量,为new myPromise类的对象。参数为一个函数,函数有两个参数,参数1代表需要调用成功逻辑,参数2表示需要调用失败逻辑

2pro对象这个时候调用了thenFun方法,将thenFun中定义的两个回调函数分别push添加到类中的回调数组中,这里失败添加到failCallBackList

3.计时器异步任务在执行完毕之后,rej('失败')调用,就将'失败'这一个值赋值给了rejectReason,并且修改了状态值为rejected

4.执行failCallBackList数组中函数,当然了,这里就一个,就是thenFun方法中第二个函数,将rejectReason作为参数调用该函数

5.然后就在thenFun函数中获取到了异步的失败值

关键就在这里,这里懂了,其实后续的很多东西都能好理解了,这里要是不懂,就多看几遍

实现类的resolve,reject以及catch方法

promise是可以这样使用的

        Promise.resolve('成功').then(res=>{console.log(res,'成功的值')})Promise.reject('失败').catch(rej=>{console.log(rej,'失败的值')})

所以这里我们就需要实现myPromise类中的静态方法resolve和reject,以及处理reject的catch方法

思路

1.调用了resolve和reject之后,需要调用then方法,所以调用这两个方法之后,返回的一定是一个promise对象,因为只有promise对象才可以调用then方法

2.catch方法其实和then方法没有什么本质的区别,所以可以直接让catchFun调用then方法,只是传参不一样而已

3.需要处理successCallBackList和failCallBackList为空的错误,因为我们这次没有往数组里添加回调函数,successCallBackList[0]()就会报错

代码实现

    //resolve处理函数resolveFun = (value) => {console.log(value, '成功的值')this.status = 'fulfilled'  //改变状态为成功this.resolveValue = value  //赋值成功值console.log(this.successCallBackList, '成功的回调函数列表')//处理数组为空时报错if(this.successCallBackList.length>0){this.successCallBackList[0](value)}}//reject处理函数rejectFun = (reason) => {console.log(reason, '失败的值')this.status = 'rejected'  //改变状态为成功this.rejectReason = reason  //赋值成功值console.log(this.failCallBackList, '失败的回调函数列表')//处理数组为空时报错if(this.failCallBackList.length>0){this.failCallBackList[0](reason)}}//then实例方法thenFun = (resolveCallBack, rejectCallBack) => {// console.log('测试then方法是否可以使用')this.successCallBackList.push(resolveCallBack)this.failCallBackList.push(rejectCallBack)}//catch实例方法catchFun = (reason)=>{//拿到失败值直接给thenFun就可以了this.thenFun(null,reason)}//promise直接调用resolve方法:myPromise.resolve('成功').thenFun(...)static resolve = (value)=>{ //完了需要调用thenFun方法,所以必然是返回一个promise对象,所以需要new myPromisereturn new myPromise(resolve=>resolve(value))  }//promise直接调用reject方法:myPromise.reject('失败').catchFun(...)static reject = (reason)=>{//resolve思路一致,返回promise对象return new myPromise(reject=>reject(reason))}

测试一下

        myPromise.resolve('成功').thenFun(res=>{console.log(res,'成功的值')})myPromise.reject('失败').catchFun(rej=>{console.log(rej,'失败的值')})

第一阶段总结

其实这一阶段的代码算是结束了,总结一下功能:

1.实现了Promise类的基本结构

2.可以实现基本的then和catch异步取值,(当前仅限于常规值类型)

3.可以实现resolve和reject静态方法的调用

当前总体代码如下

class myPromise{//new myPromise((res,rej)=>{res('成功')})//new myPromise((res,rej)=>{rej('失败')})constructor(proFun){  //这里的proFun就是:(res,rej)=>{res('成功')proFun(this.resolveFun,this.rejectFun)    }status = 'pengding' //状态resolveValue = null  //成功的值rejectReason = null  //失败的值successCallBackList = []  //成功回调集合failCallBackList = []   //失败回调集合//resolve处理函数resolveFun = (value) => {console.log(value, '成功的值')this.status = 'fulfilled'  //改变状态为成功this.resolveValue = value  //赋值成功值console.log(this.successCallBackList, '成功的回调函数列表')//处理数组为空时报错if(this.successCallBackList.length>0){this.successCallBackList[0](value)}}//reject处理函数rejectFun = (reason) => {console.log(reason, '失败的值')this.status = 'rejected'  //改变状态为成功this.rejectReason = reason  //赋值成功值console.log(this.failCallBackList, '失败的回调函数列表')//处理数组为空时报错if(this.failCallBackList.length>0){this.failCallBackList[0](reason)}}//then实例方法thenFun = (resolveCallBack, rejectCallBack) => {// console.log('测试then方法是否可以使用')this.successCallBackList.push(resolveCallBack)this.failCallBackList.push(rejectCallBack)}//catch实例方法catchFun = (reason)=>{//拿到失败值直接给thenFun就可以了this.thenFun(null,reason)}//promise直接调用resolve方法:myPromise.resolve('成功').thenFun(...)static resolve = (value)=>{ //完了需要调用thenFun方法,所以必然是返回一个promise对象,所以需要new myPromisereturn new myPromise(resolve=>resolve(value))  }//promise直接调用reject方法:myPromise.reject('失败').catchFun(...)static reject = (reason)=>{//resolve思路一致,返回promise对象return new myPromise(reject=>reject(reason))}//promise直接调用all方法:myPromise.all[pro1,pro2]static all = ()=>{}
}

第二阶段

我们需要考虑当下几种情况:

1.处理预期之外的错误,如果使用者没有按照我们预期的一样传递参数,那么就应该有错误处理机制,这里就需要使用try catch语法

2.then方法还不完善,比如我们resolve并不是传递的常规的值,而是一个新的promise,这里就需要对resolve和reject的值进行多种情况处理

3.resolve和reject类方法需要考虑传入promise而非值类型的情况

try catch错误处理机制

思路

let pro = new myPromise((res,rej)=>{console.log(a.b)
})
pro.thenFun(res=>{console.log('成功')
},rej=>{console.log('失败')
})

这里很明显,a.b肯定会报错

但是我们不应该让这个错误去阻断后续的执行,并且希望promise能把这个错误保存下来,让then方法中获取这个回调函数的执行失败状态,就需要如下处理

给proFun添加try catch错误处理机制

代码实现

    constructor(proFun){  //这里的proFun就是:(res,rej)=>{res('成功')try{proFun(this.resolveFun,this.rejectFun)    }catch(err){this.rejectFun(err)}  }

测试一下

then方法完善

思路

promise可以这样使用

        //promise本身let pro1 = new Promise((res,rej)=>{setTimeout(()=>{res(Promise.resolve('成功'))},1000)})pro1.then(res=>{console.log(res,'Promise本身的成功值')})//自定义的myPromiselet pro2 = new myPromise((res,rej)=>{setTimeout(()=>{res(Promise.resolve('成功'))},1000)})pro2.thenFun(res=>{console.log(res,'当前自定义myPromise的成功值')})

下面的是我们自定义myPromise的输出过程,由此可看,在如下的时候,我们获取的就是一个Promise

 所以后续执行,返回的自然也是一个promise

所以,then方法关键就在于如果获取的是新的promise,就需要对它进行一个处理

代码实现(全部代码)

因为这次改动会很大,所以我就把主要注释都写到代码里面了,以下是全部代码

class myPromise{//new myPromise((res,rej)=>{res('成功')})//new myPromise((res,rej)=>{rej('失败')})constructor(proFun){  //这里的proFun就是:(res,rej)=>{res('成功')try{proFun(this.resolveFun,this.rejectFun)    }catch(err){this.rejectFun(err)}  }status = 'pengding' //状态resolveValue = null  //成功的值rejectReason = null  //失败的值successCallBackList = []  //成功回调集合failCallBackList = []   //失败回调集合//resolve处理函数resolveFun = (value) => {if (this.status !== 'pengding') returnthis.status = 'fulfilled'  //改变状态为成功this.resolveValue = value  //赋值成功值//处理数组为空时报错if(this.successCallBackList.length>0){this.successCallBackList.shift()(this.resolveValue)}}//reject处理函数rejectFun = (reason) => {if (this.status !== 'pengding') returnthis.status = 'rejected'  //改变状态为成功this.rejectReason = reason  //赋值成功值//处理数组为空时报错if(this.failCallBackList.length>0){this.failCallBackList.shift()(this.rejectReason)}}//then实例方法thenFun = (resolveCallBack, rejectCallBack) => {//一般情况下,这里的两个参数都是res和rej的回调函数//如then(res=>{console.log(res,'成功值')},rej=>{console.log(rej,'失败值')})//如果这里我们没有定义res或者rej,这里就需要默认赋值一个函数,参数一成功回调,参数二失败回调抛出错误resolveCallBack = resolveCallBack || (value => this.resolveValue)rejectCallBack = rejectCallBack || (reason => {throw this.rejectReason})//then方法是需要判断你获取的值究竟是值还是一个新的promise,这里我们用myPromise包装一下let newPromise = new myPromise((res,rej)=>{//这里就需要判断promise的状态了switch(this.status){//状态未定case 'pengding'://当你使用thenFun方法了,并且状态为pengding时,就需要向回调列表中添加任务this.successCallBackList.push(()=>{try{this.globalFun(newPromise,resolveCallBack,this.resolveValue,res,rej)}catch(err){rej(err)}})this.failCallBackList.push(()=>{try{this.globalFun(newPromise,rejectCallBack,this.rejectReason,res,rej)}catch(err){rej(err)}})break//成功case 'fulfilled':setTimeout(()=>{try{this.globalFun(newPromise,resolveCallBack,this.resolveValue,res,rej)}catch(err){rej(err)}})break//失败case 'rejected':setTimeout(()=>{try{this.globalFun(newPromise,rejectCallBack,this.rejectReason,res,rej)}catch(err){rej(err)}})break}})return newPromise}//公共方法,这里是用来进行逻辑判断的,then方法遇到各种情况,都需要在这个公共方法里处理一下,然后再去执行自己应该做的事情/*** * @param {*} newPromise new的一个promise,作为thenFun的返回值* @param {*} callBack 来自thenFun的定义,或者是resolve函数,或者是reject函数,总之这个参数就是根据状态调用的* @param {*} value resolveValue || rejectReason* @param {*} resCallBack new promise的成功回调* @param {*} rejCallBack new promise的失败回调* @returns */globalFun(newPromise,callBack,value,resCallBack,rejCallBack){//如果callBackValue是一个promise对象,比如如下情况//pro.then(res=>{//  return new myPromise(resolve=>{//     resolve('成功')//  })//})//如果value的值是一个myPromise对象,就必须把它拆开来处理,利用递归在传递给globalFun,让globalFun里面的value是一个常规值if(value instanceof myPromise){//成功状态if(value.status === 'fulfilled'){this.globalFun(newPromise,callBack,value.resolveValue,resCallBack,rejCallBack)}else if(value.status === 'rejected'){//失败状态this.globalFun(newPromise,callBack,value.resolveValue,resCallBack,rejCallBack)}}else{//其实获取了具体的异步值,下面这行代码就是将异步值给返回出去了let callBackValue = callBack(value)//如果已经有值有状态了,就不需要再往下走了//这里的场景就是你异步操作又返回了一个promise的值if(callBackValue instanceof myPromise){//异步值还是promise对象,再返回去拿值去吧callBackValue.thenFun(resCallBack,rejCallBack)}else{  //如果不是promise对象,就使用成功回调if(this.resolveValue instanceof myPromise){this.resolveValue.thenFun(res=>{this.resolveValue = resresCallBack(res)},rej=>{rejCallBack(rej)})}else{resCallBack(callBackValue)}}}}//catch实例方法catchFun = (reason)=>{//拿到失败值直接给thenFun就可以了return this.thenFun(null,reason)}//promise直接调用resolve方法:myPromise.resolve('成功').thenFun(...)static resolve = (value)=>{ //完了需要调用thenFun方法,所以必然是返回一个promise对象,所以需要new myPromisereturn new myPromise(resolve=>resolve(value))  //promise直接调用reject方法:myPromise.reject('失败').catchFun(...)static reject = (reason)=>{//resolve思路一致,返回promise对象return new myPromise(reject=>reject(reason))}//promise直接调用all方法:myPromise.all[pro1,pro2]static all = ()=>{}
}//测试

测试一下

异步值是promise
        let pro1 = new myPromise((res,rej)=>{setTimeout(()=>{res(myPromise.resolve('成功的promise=>值'))// res('成功')},3000)})pro1.thenFun(res=>{console.log(res,'当前自定义myPromise的成功值1')},rej=>{console.log(rej,'当前自定义myPromise的失败值2')})let pro2 = new myPromise((res,rej)=>{setTimeout(()=>{rej(myPromise.resolve('失败的promise=>值'))// res('成功')},5000)})pro2.thenFun(res=>{console.log(res,'当前自定义myPromise的成功值1')},rej=>{console.log(rej,'当前自定义myPromise的失败值2')})

异步值是普通值
        let pro1 = new myPromise((res,rej)=>{setTimeout(()=>{// res(myPromise.resolve('成功的promise=>值'))res('成功')},3000)})pro1.thenFun(res=>{console.log(res,'当前自定义myPromise的成功值1')},rej=>{console.log(rej,'当前自定义myPromise的失败值2')})let pro2 = new myPromise((res,rej)=>{setTimeout(()=>{// rej(myPromise.resolve('失败的promise=>值'))res('成功')},5000)})pro2.thenFun(res=>{console.log(res,'当前自定义myPromise的成功值1')},rej=>{console.log(rej,'当前自定义myPromise的失败值2')})

链式调用

先看一下内置Promise的效果

 //层层依赖形成执行链let pro = new Promise(res=>{setTimeout(()=>{res('初始化成功')})})pro.then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res,'第一层链')resolve(res,'第一层返回成功值')}, 2000)})}).then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res,'第二层链')resolve('第二层返回成功值')}, 2000)})}).then(res => {return new Promise(resolve => {setTimeout(() => {console.log(res,'第三层链')resolve('第三层返回成功值')}, 2000)})}).then(res=>{console.log(res,'最终的值')})

我们自己的

//自己的myPromise链式调用
let pro = new myPromise(res=>{setTimeout(()=>{res('初始化成功自定义的')})})pro.thenFun(res => {return new myPromise(resolve => {setTimeout(() => {console.log(res,'第一层链自定义的')resolve(res,'第一层返回成功值')}, 2000)})
}).thenFun(res => {return new myPromise(resolve => {setTimeout(() => {console.log(res,'第二层链自定义的')resolve('第二层返回成功值')}, 2000)})
}).thenFun(res => {return new myPromise(resolve => {setTimeout(() => {console.log(res,'第三层链自定义的')resolve('第三层返回成功值')}, 2000)},reject=>{})
}).thenFun(res=>{console.log(res,'最终的值自定义的')
})

总结

第二阶段是promise最绕的阶段,因为在这里函数套函数,递归等等,需要好好看。

之前看promise源码,就属then里面的处理是最复杂的

说真的,这里我其实我写的时候,也是不停地调试,才给整出来的。思路很关键,但更重要的还是动手去写,我这里在自己编写的阶段,至少打印了20个console.log。也是踩坑踩出来的。

多看,强化理解,多练!!!

第三阶段

这里我们其实已经不想写太多了,在写下去估计很多人也没耐心看了。

好吧,我承认,我这篇文章写的也是挺心累的,这是第二天了

第三阶段,我就把类的resolve和reject完善一下,并且把all方法的实现完成

完善类的resolve和reject

思路

1.Promise.resolve(value),这个value可以是一个常规的值,也可以是一个new Promise(...),这样的话我们就需要对这两种情况做分别处理

2.reject同理

代码实现

    static resolve = (value)=>{ //完了需要调用thenFun方法,所以必然是返回一个promise对象,所以需要new myPromise//value是myPromise对象,就返回他if(value instanceof myPromise){return value}else{//value是普通值,就给包装成一个myPromisereturn new myPromise(resolve=>resolve(value))  }}//promise直接调用reject方法:myPromise.reject('失败').catchFun(...)static reject = (reason)=>{//和resolve思路一致if(reason instanceof myPromise){return reason}else{return new myPromise(reject=>reject(reason))}}

测试一下

let pro1 = new Promise(res=>{setTimeout(()=>{res('promise成功值')},2000)
})
Promise.resolve(pro1).then(res=>{console.log(res,'成功的值')
})let pro2 = new myPromise(res=>{setTimeout(()=>{res('promise成功值')},1000)
})
myPromise.resolve(pro2).thenFun(res=>{console.log(res,'成功的值自定义的myPromise')
})

实现all方法

思路

思路很简答,对于数组中promise进行依次执行,用计数器思想,全部执行完毕返回结果

代码实现

注释我写好了,一看就懂

    static all = (proList)=>{console.log(proList,'liebiao')let resultList = []let num = 0return new myPromise((resolve,reject)=>{let pushResult = (key,value)=>{resultList[key] = valuenum++if(num === proList.length){resolve(resultList)}}proList.forEach((item,index)=>{if(item instanceof myPromise){console.log('是myPromise类型')item.thenFun(res =>{console.log(res,'每次执行结果')pushResult(index,res)},rej=>{reject(rej)})}else{pushResult(index,item)}})})}

测试一下

let pro1 = new myPromise((res,rej)=>{setTimeout(()=>{res('成功1')},1000)
})
let pro2 = new myPromise((res,rej)=>{setTimeout(()=>{res('成功2')},2000)
})
let pro3 = new myPromise((res,rej)=>{setTimeout(()=>{res('成功3')},3000)
})
myPromise.all([pro1,pro2,pro3]).thenFun(res=>{console.log(res,'全部执行完毕的结果')
})

总结

没啥多说的,第三阶段的比较简单,我想只要第二阶段的then看明白了,应该没啥问题

心得体会

其实还有很多方法没有写,但是我感觉写到这里基本上对promise本身的理解也差不多太多了。

这篇文章是我从头到尾一字一字敲的,感觉还是付出了心血滴...

核心就在thenFun方法的实现上,then的实现你弄懂了,基本上就没啥大问题了。

感觉还行的给个点赞,收藏,关注吧!!!

附上全部代码

class myPromise{//new myPromise((res,rej)=>{res('成功')})//new myPromise((res,rej)=>{rej('失败')})constructor(proFun){  //这里的proFun就是:(res,rej)=>{res('成功')try{proFun(this.resolveFun,this.rejectFun)    }catch(err){this.rejectFun(err)}  }status = 'pengding' //状态resolveValue = null  //成功的值rejectReason = null  //失败的值successCallBackList = []  //成功回调集合failCallBackList = []   //失败回调集合//resolve处理函数resolveFun = (value) => {if (this.status !== 'pengding') returnthis.status = 'fulfilled'  //改变状态为成功this.resolveValue = value  //赋值成功值//处理数组为空时报错if(this.successCallBackList.length>0){this.successCallBackList.shift()(this.resolveValue)}}//reject处理函数rejectFun = (reason) => {if (this.status !== 'pengding') returnthis.status = 'rejected'  //改变状态为成功this.rejectReason = reason  //赋值成功值//处理数组为空时报错if(this.failCallBackList.length>0){this.failCallBackList.shift()(this.rejectReason)}}//then实例方法thenFun = (resolveCallBack, rejectCallBack) => {//一般情况下,这里的两个参数都是res和rej的回调函数//如then(res=>{console.log(res,'成功值')},rej=>{console.log(rej,'失败值')})//如果这里我们没有定义res或者rej,这里就需要默认赋值一个函数,参数一成功回调,参数二失败回调抛出错误resolveCallBack = resolveCallBack || (value => this.resolveValue)rejectCallBack = rejectCallBack || (reason => {throw this.rejectReason})//then方法是需要判断你获取的值究竟是值还是一个新的promise,这里我们用myPromise包装一下let newPromise = new myPromise((res,rej)=>{//这里就需要判断promise的状态了switch(this.status){//状态未定case 'pengding'://当你使用thenFun方法了,并且状态为pengding时,就需要向回调列表中添加任务this.successCallBackList.push(()=>{try{this.globalFun(newPromise,resolveCallBack,this.resolveValue,res,rej)}catch(err){rej(err)}})this.failCallBackList.push(()=>{try{this.globalFun(newPromise,rejectCallBack,this.rejectReason,res,rej)}catch(err){rej(err)}})break//成功case 'fulfilled':setTimeout(()=>{try{this.globalFun(newPromise,resolveCallBack,this.resolveValue,res,rej)}catch(err){rej(err)}})break//失败case 'rejected':setTimeout(()=>{try{this.globalFun(newPromise,rejectCallBack,this.rejectReason,res,rej)}catch(err){rej(err)}})break}})return newPromise}//公共方法,这里是用来进行逻辑判断的,then方法遇到各种情况,都需要在这个公共方法里处理一下,然后再去执行自己应该做的事情/*** * @param {*} newPromise new的一个promise,作为thenFun的返回值* @param {*} callBack 来自thenFun的定义,或者是resolve函数,或者是reject函数,总之这个参数就是根据状态调用的* @param {*} value resolveValue || rejectReason* @param {*} resCallBack new promise的成功回调* @param {*} rejCallBack new promise的失败回调* @returns */globalFun(newPromise,callBack,value,resCallBack,rejCallBack){//如果callBackValue是一个promise对象,比如如下情况//pro.then(res=>{//  return new myPromise(resolve=>{//     resolve('成功')//  })//})//如果value的值是一个myPromise对象,就必须把它拆开来处理,利用递归在传递给globalFun,让globalFun里面的value是一个常规值if(value instanceof myPromise){//成功状态if(value.status === 'fulfilled'){this.globalFun(newPromise,callBack,value.resolveValue,resCallBack,rejCallBack)}else if(value.status === 'rejected'){//失败状态this.globalFun(newPromise,callBack,value.resolveValue,resCallBack,rejCallBack)}}else{//其实获取了具体的异步值,下面这行代码就是将异步值给返回出去了let callBackValue = callBack(value)//如果已经有值有状态了,就不需要再往下走了//这里的场景就是你异步操作又返回了一个promise的值if(callBackValue instanceof myPromise){//异步值还是promise对象,再返回去拿值去吧callBackValue.thenFun(resCallBack,rejCallBack)}else{  //如果不是promise对象,就使用成功回调if(this.resolveValue instanceof myPromise){this.resolveValue.thenFun(res=>{this.resolveValue = resresCallBack(res)},rej=>{rejCallBack(rej)})}else{resCallBack(callBackValue)}}}}//catch实例方法catchFun = (reason)=>{//拿到失败值直接给thenFun就可以了return this.thenFun(null,reason)}//promise直接调用resolve方法:myPromise.resolve('成功').thenFun(...)static resolve = (value)=>{ //完了需要调用thenFun方法,所以必然是返回一个promise对象,所以需要new myPromiseif(value instanceof myPromise){return value}else{return new myPromise(resolve=>resolve(value))  }}//promise直接调用reject方法:myPromise.reject('失败').catchFun(...)static reject = (reason)=>{//和resolve思路一致if(reason instanceof myPromise){return reason}else{return new myPromise(reject=>reject(reason))}}//promise直接调用all方法:myPromise.all[pro1,pro2]static all = (proList)=>{console.log(proList,'liebiao')let resultList = []let num = 0return new myPromise((resolve,reject)=>{let pushResult = (key,value)=>{resultList[key] = valuenum++if(num === proList.length){resolve(resultList)}}proList.forEach((item,index)=>{if(item instanceof myPromise){console.log('是myPromise类型')item.thenFun(res =>{console.log(res,'每次执行结果')pushResult(index,res)},rej=>{reject(rej)})}else{pushResult(index,item)}})})}
}//测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/582506.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(11)

接前一篇文章:《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(10) 1.3 PCI总线的存储器读写总线事务 1.3.2 Posted和Non-Posted传送方式 PCI总线规定了两类数据传送方式,分别是Posted和Non-Posted数据传送…

关于Redis面试题

前言 之前为了准备面试,收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文:https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv Redis 是什么 全名:远程字典服务。这是一个开源的在内存中的数据结构存…

硅像素传感器文献调研(二)

写在前面:从上篇文章的参考文献中看到一篇文献,现在也精读一下,今天还有一个任务是把上篇文献整体脉络用流程图的形式完整梳理一下。 哈哈哈哈哈哈:代表没太搞明白的部分 如何写论文: 引言部分:基础理论…

Python入门知识点分享——(十一)if条件语句

if条件语句是一种编程语言中用于控制程序流程的结构。它根据一个条件的真假来决定执行不同的代码块。 if条件语句通常由if关键字、一个条件表达式和一个代码块组成。条件表达式可以是一个返回布尔值的表达式,如果条件为真,则执行代码块中的代码&#xf…

01_软件测试

01_软件测试 学习目标 1、能复述软件测试的定义 2、能说出7种测试分类的区别 3、能说出质量模型的重点5项 4、能说出测试流程的6个步骤 5、能说出测试模板8个要素 认识软件及测试 什么是软件 软件:控制计算机硬件工作的工具 软件的基本组成 软件生产过程 什么是软…

vue多条数据渲染(带图片)

我在这用的为接口数据&#xff1a; 先调用接口获取需要的数据: 然后用&#xff1a;data绑定需要渲染的数据&#xff1b;&#xff08;记得包裹在<el-table>标签中&#xff09; 然后以此循环渲染数据&#xff1b;那怎么渲染出来图片呢&#xff1f; 在<el-table-column…

Vue3-25-路由-路由的基本使用

对路由的理解 路由 &#xff1a; 就是前端对页面路径的拦截&#xff0c;根据不同的路径渲染不同的组件&#xff0c; 从而实现单页应用中的页面局部刷新的功能。安装路由依赖 根据使用的不同的包管理工具采用不同的命令&#xff0c; 常见的三种包管理工具和对应的命令如下&…

day44 1228

作业1&#xff1a; #include <iostream>using namespace std;class Person {int *age;string &name; public:Person(int age,string &name):age(new int(age)),name(name){cout << "Person的构造函数" <<endl;}~Person(){delete age;cout…

【Java系列】多线程案例学习——基于阻塞队列实现生产者消费者模型

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习JavaEE的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录…

如何在Mac中设置三指拖移,这里有详细步骤

三指拖移手势允许你选择文本&#xff0c;或通过在触控板上用三指拖动窗口或任何其他元素来移动它。它可以用于快速移动或调整窗口、文件或图像在屏幕上的位置。 然而&#xff0c;这个手势在默认情况下是禁用的&#xff0c;因此在本教程中&#xff0c;我们将向你展示如何在你的…

数据库系统原理例题之——SQL 与关系数据库基本操作

SQL 与关系数据库基本操作 第四章 SQL 与关系数据库基本操作【例题】一 、单选题二 、填空题三 、简答题四 、设计题 【答案&解析】一、单选题二、填空题三、简答题四、设计题 【延伸知识点】【延伸知识点答案&解析】 第四章 SQL 与关系数据库基本操作 【例题】 一 、…

springboot整合minio做文件存储

一,minio介绍 MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等&#xff0c;而一个对象文件可以是任意大小&…

verilog rs232串口模块

前面发了个发送模块&#xff0c;这次补齐&#xff0c;完整。 串口计数器&#xff0c;波特率适配 uart_clk.v module uart_clk(input wire clk,input wire rst_n,input wire tx_clk_en,input wire rx_clk_en,input wire[1:0] baud_sel,output wire tx_clk,output wire rx_clk )…

Kubernetes快速实战与核心原理剖析

K8S 概览 K8S 是什么 K8S 官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ K8S 是 Kubernetes 的全称&#xff0c;源于希腊语&#xff0c;意为“舵手”或“飞行员”。Kubernetes 是用于自动部署、扩缩和管理容器化应用程序的开源系统。 Kubernetes 源自 Google 15 年…

EDKII:第一个Helloworld

目录 0 说明 1 步骤 1.1 简介 1.2 创建新文件 1.3 创建printhelloworld.c、printhelloworld.inf&#xff1a; 1.4 修改MdeModulePkg\MdeModulePkg.dsc 1.5 修改EmulatorPkg\EmulatorPkg.dsc 1.6 运行 0 说明 上篇文章记录了如何安装UEFI环境&#xff0c;在这里将会写下…

c++ / day03

1. 定义一个Person类&#xff0c;包含私有成员&#xff0c;int *age&#xff0c;string &name&#xff0c;一个Stu类&#xff0c;包含私有成员double *score&#xff0c;Person p1&#xff0c;写出Person类和Stu类的特殊成员函数&#xff0c;并写一个Stu的show函数&#xf…

CodeWhisperer——轻松使用一个超级强大的工具

CodeWhisperer 简介 CodeWhisperer是亚⻢逊云科技出品的一款基于机器学习的通用代码生成器&#xff0c;可实时提供代码建议。 CodeWhisperer有以下几个主要用途&#xff1a; 解决编程问题&#xff0c;提供代码建议&#xff0c;学习编程知识等等&#xff0c;并且CodeWhisper…

基于人工势场法的航线规划

MATLAB2016b可以运行 基于人工势场法的航线规划资源-CSDN文库

常用的 linux 命令

常用的 linux 命令 1.从其他机器拷贝文件夹2.查看哪个程序在用特定端口3.实时监控日志文件内容4.查看指定用户拥有的进程5.查看磁盘空间使用情况6.文件搜索which&#xff08;whereis&#xff09; 显示系统命令所在目录find 查找任何文件或目录1&#xff09; 根据文件名称查找2)…

磁盘——磁盘管理与文件系统

目录 一、在linux中使用硬盘分三步 1、分区 2、文件系统&#xff08;管理大小权限。日志恢复&#xff09; 3、挂载&#xff08;硬盘和系统文件做关联&#xff0c;使用文件夹使用系统&#xff09; 二、磁盘结构 三、MBR与GPT磁盘分区 1、分区的原因&#xff0c;为什么分区…