2024-04-09
javascript
00
请注意,本文编写于 151 天前,最后修改于 112 天前,其中某些信息可能已经过时。

目录

手写Promise,方便更清晰的认识内部处理什么
观察Promise的写法
模拟Promise类的写法
1. 通过上方观察Promise的写法,一个Promise构造函数中,会有一个参数(函数),由外界传递,并且这个参数(函数)会有两个回调函数,分别是‘resolve’和‘reject’。所以我写出了下方代码
2.写出resolve和reject处理函数
3. 补充状态逻辑
4.对于初始化状态的设定
完善.then的方法 用来接受成功或失败的值
错误处理
异步任务
改造未有异步情况下的执行顺序问题
改造有异步(重点、核心、异步队列)
基本已实现Promise核心代码
实现.resolve函数
参数是普通数据
参数是Promise呢?
thenable对象
没有参数的情况
实现.reject函数
实现prototype.catch函数
实现prototype.finally函数
实现.all函数
补充细节
补充细节2
实现.allSettled函数
实现.race函数
实现any函数
最终代码

这里不过多的赘述promise是什么,既然点开此文章,就代表你对js已经很熟练使用了。所以,接下来给我一点时间,让我在这详细分步骤的手写promise核心区域,并且包括一些边界情况。

手写Promise,方便更清晰的认识内部处理什么

包括:如等待行异步?状态之间的关系?链式操作?

观察Promise的写法

js
const pro = new Promise((resolve,reject)=>{ resolve('成功') reject('失败') })

以上就是一个简单的Promise案例,其中resolve表示成功后的回调函数,reject表示失败后的回调函数。

手写Promise必须要明白他内部怎么回事,Promise本身会有三个状态,分别是"等待(PENDING)","成功(FULFILLED)","失败(REJECTED)"。其中默认Promise的状态为“等待”,状态变化只能是“成功”、“失败”,只要状态一发生变化,后续就不可逆,不可再更改状态(可以理解:你打开王者荣耀,随机进了一局排位赛,比赛结果只有输赢,并且当前输赢已定局不能更改)。

绘图说明:

promise状态关系.svg

模拟Promise类的写法

1. 通过上方观察Promise的写法,一个Promise构造函数中,会有一个参数(函数),由外界传递,并且这个参数(函数)会有两个回调函数,分别是‘resolve’和‘reject’。所以我写出了下方代码

js
class MyPromise{ constructor(func){ func(resolve,reject) } }

通过上方草率的写出了个Class,发现个问题:resolvereject需要怎么写呢?应该写在哪里呢?

2.写出resolvereject处理函数

首先需要知道,resolve和reject函数,是在constructor构造函数内调用,所以,我们需要手写在当前自定义的Promise内定义这两个方法:

js
class MyPromise{ constructor(func){ func(resolve,reject) } // 处理Promise回调函数中成功的逻辑 resolve(){} // 处理Promise回调函数中错误、失败的逻辑 reject(){} }

此时我们定义好对应的状态处理函数,在看,是不是constructor的func的参数,怎么调用呢?这时候,我们需要使用关键字“this”来指向这个函数

js
class MyPromise{ constructor(func){ // 使用this指向我们的处理函数 func(this.resolve,this.reject) } // 处理Promise回调函数中成功的逻辑 resolve(){} // 处理Promise回调函数中错误、失败的逻辑 reject(){} }

3. 补充状态逻辑

完善Promise的状态。"等待(PENDING)","成功(FULFILLED)","失败(REJECTED)",有个疑问,这几个状态我们应该在代码中怎么个展示形式?是放在一个对象里?是放在这个类的属性里?还是放在静态资源里?

我选择放在静态资源中,如果放在this.status = {x:1,y:2,z:3}是不是又多创建个对象?是吧

js
class MyPromise{ // 所以,我把状态写在静态资源中 static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; constructor(func){ func(this.resolve,this.reject) } resolve(){} reject(){} }

4.对于初始化状态的设定

Promise第一次初始化时,会有一个保存当前状态的一个值,这个值被本class共享使用,只有通过resolve或reject回调函数才会更改状态。so 下面补充下代码

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; // 当前状态(这个值被本class共享使用) currentStatus = null; constructor(func){ // 初始化时,第一件事就是改变下状态 this.currentStatus = MyPromise.PENDING; // 等待状态 func(this.resolve,this.reject) } resolve(){} reject(){} }

resolvereject函数中,改变对应的状态。在看下我们使用这两个函数时,会有参数带入是吧,思考,传递过来的参数,我们会在.then的时候给返回出去,应该这个参数放到哪里呢?所以我们继续补充完整。

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; // 存放不管是操作成功或失败的参数 currentRes = null; constructor(func){ this.currentStatus = MyPromise.PENDING; // 等待状态 func(this.resolve,this.reject) } // 处理Promise回调函数中成功的逻辑 resolve(res){ this.currentStatus = MyPromise.FULFILLED // 完成状态 this.currentRes = res; } // 处理Promise回调函数中错误、失败的逻辑 reject(rej){ this.currentStatus = MyPromise.REJECTED // 失败状态 this.currentRes = rej; } }

因为Promise的状态只能更改一次,所以,我们需要更严谨的控制resolvereject回调函数中的逻辑。

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ this.currentStatus = MyPromise.PENDING; func(this.resolve,this.reject) } // 处理Promise回调函数中成功的逻辑 resolve(res){ // 只有当状态为初始值的时候,我才能走里面代码逻辑。 if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } // 处理Promise回调函数中错误、失败的逻辑 reject(rej){ // 只有当状态为初始值的时候,我才能走里面代码逻辑。 if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } }

完善.then的方法 用来接受成功或失败的值

思考🤔:.then是怎么写的呢?它接收几个参数?每个参数什么作用?

答:两个参数、第一个参数是reslove的成功状态的回调,第二个是reject失败状态后回调。

原版这样写:

js
const pro = new Promise((resolve,reject)=>{ resolve('成功了') reject('失败了') }) pro.then( (res)=>{ console.log('.then成功时候拿到的值',res) }, (err)=>{ console.log('.then失败后拿到的值',err) } )

so 我们完善.then的方法。

要考虑几点问题,.then是做什么的?参数怎么写?返回什么东西?

  1. then是接收promise最后状态的接收器
  2. 参数包括两个回调函数,并且验证是不是函数
  3. 返回Promise实例。可以链式调用

so 一步一步来

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ this.currentStatus = MyPromise.PENDING; func(this.resolve,this.reject) } resolve(res){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } reject(rej){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } // .then的时候,返回状态已改变后的值,传入回调函数中。而且要判断状态,如下 then(onFulfilleder,onRejecteder){ // 验证是不是函数,如果不是,默认写入个函数,防止报错 onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.FULFILLED){ let x = onFulfilleder(this.currentRes); // 验证当前值是不是promise实例上的,如果不是,返回当前promise的resolve包装下 x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }else if(this.currentStatus === MyPromise.REJECTED){ let x = onRejecteder(this.currentRes); // 验证当前值是不是promise实例上的,如果不是,返回当前promise的reject包装下 x instanceof MyPromise ? x.then(resolve,reject) : reject(x); } }) } }

看起来没什么问题了,我们打印一下,看看同步的方式能否成功呢

so 我来简化下代码,去除注释,添加打印日志,我们试试

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ this.currentStatus = MyPromise.PENDING; func(this.resolve,this.reject) } resolve(res){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } reject(rej){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } then(onFulfilleder,onRejecteder){ onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.FULFILLED){ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }else if(this.currentStatus === MyPromise.REJECTED){ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); } }) } } const pro = new MyPromise((resolve,reject)=>{ resolve('成功') reject('失败') }) pro.then(res=>{ console.log('pro.then.res',res) },err=>{ console.log('pro.then.err',err) })

image.png 啪。。。。打脸(我诚心的,让你们分析原因)

TypeError:无法读取未定义的属性(读取“currentStatus”) 分析分析吧,是不是哪块有问题呢?我们分别在关键位置上打上日志(读取或设置currentStatus的地方),因为都是this调用currentStatus, so 我们关注this,看看哪里出问题了----逐步分析下,此时带日志的代码如下

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ console.log('构造函数啦',this) // 日志1 this.currentStatus = MyPromise.PENDING; func(this.resolve,this.reject) } resolve(res){ console.log('resolve啦',this)// 日志 2 if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } reject(rej){ console.log('reject啦',this) // 日志3 if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } then(onFulfilleder,onRejecteder){ console.log('.then啦',this) // 日志4 onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.FULFILLED){ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }else if(this.currentStatus === MyPromise.REJECTED){ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); } }) } } const pro = new MyPromise((resolve,reject)=>{ resolve('成功') reject('失败') }) pro.then(res=>{ console.log('pro.then.res',res) },err=>{ console.log('pro.then.err',err) })

日志反馈结果:

image.png

不卖关子了。重点在constructor的func上的参数。

弄清----原因:首先,考虑具体是在哪里调用的这个func?弄明白之后你就知道了。

原因:外部调用MyPromise内部函数,并且没有任何指向关系。so,知道怎么做了吧

问题代码↓

JS
... constructor(func){ .... // 将被调用的函数this上下文指向当前MyPromise上解决问题 func(this.resolve.bind(this),this.reject.bind(this)) }

好了,我们完善下代码

JS
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ console.log('构造函数啦',this) // 日志1 this.currentStatus = MyPromise.PENDING; // 将被调用的函数this上下文指向当前MyPromise上解决问题 func(this.resolve.bind(this),this.reject.bind(this)) } resolve(res){ console.log('resolve啦',this)// 日志 2 if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } reject(rej){ console.log('reject啦',this) // 日志3 if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } then(onFulfilleder,onRejecteder){ console.log('.then啦',this) // 日志4 onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.FULFILLED){ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }else if(this.currentStatus === MyPromise.REJECTED){ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); } }) } } const pro = new MyPromise((resolve,reject)=>{ resolve('成功') reject('失败') }) pro.then(res=>{ console.log('pro.then.res',res) },err=>{ console.log('pro.then.err',err) })

舒服的执行完了 image.png

错误处理

假设,我们写的Promise里有报错,我们怎么处理呢?

js
const pro = new MyPromise((resolve,reject)=>{ // resolve('成功') // reject('失败') // 某个时机,捕获到了一个错误程序 throw Error('模拟报错程序') }) pro.then(res=>{ console.log('pro.then.res',res) },err=>{ console.log('pro.then.err',err) })

报错如图: 报错未捕获.png 思考捕获时机:因为是在func函数内出现的报错。我们可以针对执行func时进行try catch捕获错误并直接交给reject回调函数返回。

so 代码优化如下↓

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ this.currentStatus = MyPromise.PENDING; // 通过try和catch能捕获到使用Promise内执行代码错误运行的情况。 try{ func(this.resolve.bind(this),this.reject.bind(this)) }catch(err){ this.reject(err) } } resolve(res){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } reject(rej){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } then(onFulfilleder,onRejecteder){ onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.FULFILLED){ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }else if(this.currentStatus === MyPromise.REJECTED){ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); } }) } } const pro = new MyPromise((resolve,reject)=>{ // resolve('成功') // reject('失败') // 某个时机,捕获到了一个错误程序 throw Error('模拟报错程序') }) pro.then(res=>{ console.log('pro.then.res',res) },err=>{ console.log('pro.then.err',err) })

so 安全了 image.png

异步任务

思考:Promise如何捕获异步?先抛出答案:任务列表。下面会讲到。

先看原生执行顺序

代码:

js
console.log("1"); const pro = new Promise((resolve, reject) => { console.log("2"); resolve("成功"); console.log("3"); }); pro.then((res) => { console.log("4"); console.log("pro.then.res", res); }); console.log("5");

Promise的执行顺序: image.png

目前我们自己的 代码:

js
console.log("1"); const pro = new MyPromise((resolve, reject) => { console.log("2"); resolve("成功"); console.log("3"); }); pro.then((res) => { console.log("4"); console.log("pro.then.res", res); }); console.log("5");

MyPromise的执行顺序: image.png

改造未有异步情况下的执行顺序问题

代码:

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ this.currentStatus = MyPromise.PENDING; try{ func(this.resolve.bind(this),this.reject.bind(this)) }catch(err){ this.reject(err) } } resolve(res){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } reject(rej){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } then(onFulfilleder,onRejecteder){ onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.FULFILLED){ // 增加延迟器 setTimeout(()=>{ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }) }else if(this.currentStatus === MyPromise.REJECTED){ // 增加延迟器 setTimeout(()=>{ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); }) } }) } } console.log("1"); const pro = new MyPromise((resolve, reject) => { console.log("2"); resolve("成功"); console.log("3"); }); pro.then((res) => { console.log("4"); console.log("pro.then.res", res); }); console.log("5");

执行顺序被优化了 image.png

改造有异步(重点、核心、异步队列)

先看原生执行顺序

代码:

js
console.log("1"); const pro = new Promise((resolve, reject) => { setTimeout(() => { console.log("2"); resolve("成功"); console.log("3"); }); }); pro.then((res) => { console.log("4"); console.log("pro.then.res", res); }); console.log("5");

Promise的执行顺序: image.png

目前我们自己的 代码:

js
console.log("1"); const pro = new MyPromise((resolve, reject) => { setTimeout(() => { console.log("2"); resolve("成功"); console.log("3"); }); }); pro.then((res) => { console.log("4"); console.log("pro.then.res", res); }); console.log("5");

MyPromise的执行顺序: image.png

进行改造

思考:为什么会丢掉resolve函数?没执行吗?

排查: 我们针对resolve函数和.then函数,分别打印日志,输出当前状态。

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; constructor(func){ this.currentStatus = MyPromise.PENDING; try{ func(this.resolve.bind(this),this.reject.bind(this)) }catch(err){ this.reject(err) } } resolve(res){ console.log(`this.currentStatus resolve:`, this.currentStatus);// 我们在resolve函数调用的时候,输出此MyPromise的状态是什么,方便查找问题,针对问题作出具体步骤 if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; } } reject(rej){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; } } then(onFulfilleder,onRejecteder){ console.log(`this.currentStatus then:`, this.currentStatus);// 我们在.then函数调用的时候,输出此MyPromise的状态是什么,方便查找问题,针对问题作出具体步骤 onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.FULFILLED){ setTimeout(()=>{ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }) }else if(this.currentStatus === MyPromise.REJECTED){ setTimeout(()=>{ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); }) } }) } } console.log("1"); const pro = new MyPromise((resolve, reject) => { setTimeout(() => { console.log("2"); resolve("成功"); console.log("3"); }); }); pro.then((res) => { console.log("4"); console.log("pro.then.res", res); }); console.log("5");

此时执行上方代码,输出内容如下 1、this.currentStatus then: 等待、5、2、this.currentStatus resolve: 等待、3

image.png

通过上方日志分析:所有方法都执行了。只是他.then的时候直接拿到DENPING(等待)状态。这不是我们所期望的。

具体改造过程:

1、定义成功任务队列和失败任务队列。

2、将.then状态为DENPING(等待)时候,分别将处理函数放入对应任务队列中

3、在执行resolvereject时,从任务队列中取出并全部执行。

代码如下:

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; // 定义存放异步成功任务的列表(队列),列表内存放函数,等待时机直接执行 asyncFulfillList = []; // 定义存放异步失败任务的列表(队列),列表内存放函数,等待时机直接执行 asyncRejectList = []; constructor(func){ this.currentStatus = MyPromise.PENDING; try{ func(this.resolve.bind(this),this.reject.bind(this)) }catch(err){ this.reject(err) } } resolve(res){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; // 取出任务队列的任务执行 for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; // 取出任务队列的任务执行 for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder,onRejecteder){ onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ // 判断当前是异步的情况(只有异步是直接进入.then,状态一直是PENDING) if(this.currentStatus === MyPromise.PENDING){ // 将对应的处理函数放入对应的任务队列中 this.asyncFulfillList.push(()=>{ // 这是成功任务队列 setTimeout(()=>{ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }) }); this.asyncRejectList.push(()=>{ // 这是失败任务队列 setTimeout(()=>{ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); }) }); } if(this.currentStatus === MyPromise.FULFILLED){ setTimeout(()=>{ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }) }else if(this.currentStatus === MyPromise.REJECTED){ setTimeout(()=>{ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); }) } }) } } console.log("1"); const pro = new MyPromise((resolve, reject) => { setTimeout(() => { console.log("2"); resolve("成功"); console.log("3"); },1000); }); pro.then((res) => { console.log("4"); console.log("pro.then.res", res); }); console.log("5");

我把异步时间调整为1000毫米,并加上时间戳,方便查看差异。我们来试试执行

image.png

基本已实现Promise核心代码

核心就是如何捕获异步、状态的派发及捕获、链式.then

js
class MyPromise{ static PENDING ='等待'; static FULFILLED ='成功'; static REJECTED ='失败'; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func){ this.currentStatus = MyPromise.PENDING; try{ func(this.resolve.bind(this),this.reject.bind(this)) }catch(err){ this.reject(err) } } resolve(res){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.FULFILLED this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej){ if(this.currentStatus === MyPromise.PENDING){ this.currentStatus = MyPromise.REJECTED this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder,onRejecteder){ onFulfilleder = typeof onFulfilleder === 'function' ? onFulfilleder : (val)=>val; onRejecteder = typeof onRejecteder === 'function' ? onRejecteder : (err)=>err; return new MyPromise((resolve,reject)=>{ if(this.currentStatus === MyPromise.PENDING){ this.asyncFulfillList.push(()=>{ setTimeout(()=>{ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }) }); this.asyncRejectList.push(()=>{ setTimeout(()=>{ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); }) }); } if(this.currentStatus === MyPromise.FULFILLED){ setTimeout(()=>{ let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : resolve(x); }) }else if(this.currentStatus === MyPromise.REJECTED){ setTimeout(()=>{ let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve,reject) : reject(x); }) } }) } }

实现.resolve函数

先看下正常Promise是如何书写,在思考需准备什么

js
const pro = Promise.resolve('123') // 等同于这样书写 const pro = new Promise((resolve)=>{ resolve('123') }) pro.then(res=>{ console.log('成功了', res) })

参数是普通数据

思考🤔:

目测肯定返回一个Promise。

构造函数的方法,没有被实例,放在此类的静态资源上。

嗯对。so我们来写一下⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.resolve static resolve(value){ return new MyPromise((resolve,reject)=>{ resolve(value) }) } }

image.png 丐中丐版本已实现⬆️

我们来处理一些边界情况

参数是Promise呢?

image.png

显然,这不是我们需要的结果res: MyPromise{...}

改造!⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.resolve static resolve(value){ // 当前值如果就是一个MyPromise的值,就直接返回 if(value instanceof MyPromise){ return value } return new MyPromise((resolve,reject)=>{ resolve(value) }) } }

image.png

完美!不不不,还有问题

thenable对象

什么是thenable? 它是一个对象,并且带有then方法的对象 如下⬇️

js
let thenable = { then: function(resolve, reject) { resolve(42); } };

文档的意思是,Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。 具体请看阮一峰Promise文章

so 处理下

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.resolve static resolve(value){ // 当前值如果就是一个MyPromise的值,就直接返回 if(value instanceof MyPromise){ return value // 当遇到thenable对象时,执行对象内.then方法 }else if(value && typeof value === 'object' && value.hasOwnProperty('then')){ return new MyPromise((resolve,reject)=>{ value.then(resolve,reject) }) } return new MyPromise((resolve,reject)=>{ resolve(value) }) } }

执行完成结果:

image.png

没有参数的情况

通常,没有参数时,只是我们想让他变成一个微任务,在.then中执行一些延时逻辑

比如vue中$nextTick源码就使用到,Promise.resolve().then(callback)

我们什么都不做,跑一下代码试试,看看是不是异步的

js
console.log("start"); const pro = MyPromise.resolve(); console.log(`pro:`, pro); pro.then((res) => { console.log(`res:`, res); }); console.log(`end`);

image.png

此时,resolve方法宣告完美😍

完成resolve函数的整体代码:

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } }

实现.reject函数

先看下正常Promise是如何书写,在思考需准备什么

js
const pro = Promise.reject('出错了'); // 等同于 const pro = new Promise((resolve, reject) => reject('出错了')) pro.then(null, function (s) { console.log(s)// 出错了 });

so 我们应该只关注reject的结果是什么

Promise.reject()方法返回一个带有拒绝原因的Promise对象

直接实现⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.reject static reject(value){ return new MyPromise((resolve,reject)=>{ reject(value) }) } }

直接看结果:

image.png so 带有reject函数的整体代码:

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } }

实现prototype.catch函数

Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。 思考🤔:这属于类上面的方法,不是静态资源了,是通过实例化才能得到的方法。

so 很简单⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.catch catch(error){ return this.then(null,error); } }

验证一下:

image.png so 带有catch函数的整体代码:

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } catch(error) { return this.then(null, error); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } }

实现prototype.finally函数

finally()方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。

注意⚠️:次函数不接受任何参数。只表示promise执行完了而已。

so 怎么写呢⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.finally finally(callback){ return this.then(callback,callback); } }

验证一下:

image.png

image.png

so 带有finally函数的整体代码:

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } catch(error) { return this.then(null, error); } finally(callback) { return this.then(callback, callback); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } }

实现.all函数

解读:Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

原版写法:

js
console.log('start'); const p1 = Promise.resolve(1); const p2 = Promise.resolve(2); const p3 = Promise.resolve(3); Promise.all([p1, p2, p3]).then( (res) => { // 成功的时候是数组 console.log("MyPromise.all => full", res); }, (err) => { // 失败时是第一个reject的结果 console.log("MyPromise.all => err", err); } ); console.log('end');

分析:.all()方法接收一个数组(Promise任务数组),返回一个Promise对象,一起执行所有的异步任务,并返回结果(数组或当前失败的信息)

so 我们尝试实现一下⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.all // 接收一个数组(Promise任务数组) static all(promiseLists){ // 如果不是数组,则返回报错 if(Array.isArray(promiseLists)){ // 返回一个Promise对象,内容是正确时的数组、或失败时的信息, // 所以我们resolve回调函数中存放返回的成功的数组, // reject回调函数接收错误信息 return new MyPromise((resolve,reject)=>{ //当前执行第几个 let count = 0; // 存放执行完成后的结果(成功结果) let resList = []; // 此步骤循环执行promiseLists中的Promise for(let i = 0;i<promiseLists.length;i++){ MyPromise.resolve(promiseLists[i]).then(res=>{ //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = res; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); // 如果失败,直接返回当前失败信息 },err=>{ reject(err) }) } }) }else{ throw Error('当前all接收参数不是数组格式') } } }

看起来整体核心写完了。实际跑一下⬇️

全部都是成功时的情况

js
console.log('start'); const p1 = MyPromise.resolve(1); const p2 = MyPromise.resolve(2); const p3 = MyPromise.resolve(3); MyPromise.all([p1, p2, p3]).then( (res) => { // 成功的时候是数组 console.log("MyPromise.all => full", res); }, (err) => { // 失败时是第一个reject的结果 console.log("MyPromise.all => err", err); } ); console.log('end'); // start // end // MyPromise.all => full [ 1, 2, 3 ]

部分成功的情况

js
console.log('start'); const p1 = MyPromise.resolve(1); const p2 = MyPromise.reject(2);// 这个失败 const p3 = MyPromise.resolve(3); MyPromise.all([p1, p2, p3]).then( (res) => { // 成功的时候是数组 console.log("MyPromise.all => full", res); }, (err) => { // 失败时是第一个reject的结果 console.log("MyPromise.all => err", err); } ); console.log('end'); // start // end // MyPromise.all => err 2

补充细节

如果当数组是个空数组呢

js
console.log('start'); MyPromise.all([]).then( (res) => { // 成功的时候是数组 console.log("MyPromise.all => full", res); }, (err) => { // 失败时是第一个reject的结果 console.log("MyPromise.all => err", err); } ); console.log('end'); // start // end

发现并么有走.then后的逻辑。我们补充完整(数组为空,返回成功的状态,并且也返回该数组)

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.all static all(promiseLists){ if(Array.isArray(promiseLists)){ // 判断边界。当数组为空时,返回Promise对象的空数组 //(目的是在.then的参数的回调中能接收到此值) if(promiseLists.length===0){ return new MyPromise((resolve,reject)=>{ resolve(promiseLists) }) } return new MyPromise((resolve,reject)=>{ let count = 0; let resList = []; for(let i = 0;i<promiseLists.length;i++){ MyPromise.resolve(promiseLists[i]).then(res=>{ count++; resList[i] = res; count === promiseLists.length && resolve(resList); },err=>{ reject(err) }) } }) }else{ throw Error('当前all接收参数不是数组格式') } } }

再次运行,结果是想要的了

js
// start // end // MyPromise.all => full []

补充细节2

当我们promiseLists参数重,有部分是普通数据,我们就不需要让他在经过包装Promise对象了,因为不需要多此一举。

so 代码改造如下⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.all static all(promiseLists){ if (Array.isArray(promiseLists)) { if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } return new MyPromise((resolve, reject) => { let count = 0; let resList = []; for (let i = 0; i < promiseLists.length; i++) { // 判断当前是不是Promise对象,如果不是,我们就直接返回此数据就好 if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { count++; resList[i] = res; count === promiseLists.length && resolve(resList); }, (err) => { reject(err); } ); } else { // 打印日志 console.log('普通数据类型',promiseLists[i]) count++; resList[i] = promiseLists[i]; count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } }

so 我们验证下

js
console.log("start"); const p1 = MyPromise.resolve(1); const p2 = undefined; const p3 = MyPromise.resolve(3); MyPromise.all([p1, p2, p3]).then( (res) => { // 成功的时候是数组 console.log("MyPromise.all => full", res); }, (err) => { // 失败时是第一个reject的结果 console.log("MyPromise.all => err", err); } ); console.log(`end`); // start // 普通数据类型 undefined // end // MyPromise.all => full [ 1, undefined, 3 ]

🎉撒花,此时.all()方法完结✅

附此步骤下的所有代码:

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } catch(error) { return this.then(null, error); } finally(callback) { return this.then(callback, callback); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } // 接收一个数组(Promise任务数组) static all(promiseLists) { // 如果不是数组,则返回报错 if (Array.isArray(promiseLists)) { // 判断边界。当数组为空时,返回Promise对象的空数组 //(目的是在.then的参数的回调中能接收到此值) if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } // 返回一个Promise对象,内容是正确时的数组、或失败时的信息, // 所以我们resolve回调函数中存放返回的成功的数组, // reject回调函数接收错误信息 return new MyPromise((resolve, reject) => { //当前执行第几个 let count = 0; // 存放执行完成后的结果(成功结果) let resList = []; // 此步骤循环执行promiseLists中的Promise for (let i = 0; i < promiseLists.length; i++) { // 判断当前是不是Promise对象,如果不是,我们就直接返回此数据就好 if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = res; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); // 如果失败,直接返回当前失败信息 }, (err) => { reject(err); } ); } else { //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = promiseLists[i];// 注意这里我们直接赋值即可,不需要包装Promise对象 // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } } console.log("start"); const p1 = MyPromise.resolve(1); const p2 = undefined; const p3 = MyPromise.resolve(3); MyPromise.all([p1, p2, p3]).then( (res) => { // 成功的时候是数组 console.log("MyPromise.all => full", res); }, (err) => { // 失败时是第一个reject的结果 console.log("MyPromise.all => err", err); } ); console.log(`end`);

实现.allSettled函数

.allSettled().all()函数

相同点包括:

  1. 同时处理多个异步任务

不同的地儿包括:

  1. 当遇到reject时,不会立刻停止。反之同时收集全部信息
  2. 返回值不一样了,数组中是对象结构,包括status字段代表成功或失败、还有一个值是value/reason (value代表成功的结果,reason代表失败后的结果)

so 直接改造.all()函数即可(缝缝补补)代码如下⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.allSettled static allSettled(promiseLists){ if (Array.isArray(promiseLists)) { if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } return new MyPromise((resolve, reject) => { let count = 0; let resList = []; for (let i = 0; i < promiseLists.length; i++) { if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { count++; // 1、改造此处(成功信息),加入状态和返回值即可 resList[i] = { status:MyPromise.FULFILLED, value:res }; count === promiseLists.length && resolve(resList); }, (err) => { count++; // 3、改造此处(错误信息),加入状态和返回值即可 resList[i] = { status:MyPromise.REJECTED, reason:err }; count === promiseLists.length && resolve(resList); } ); } else { count++; // 2、改造此处(成功信息),加入状态和返回值即可 resList[i] = { status:MyPromise.FULFILLED, value:promiseLists[i] }; count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } }

验证

js
console.log("start"); const p1 = MyPromise.resolve(1); const p2 = undefined; const p3 = MyPromise.reject(3); MyPromise.allSettled([p1, p2, p3]).then((res) => { // 返回值 console.log("MyPromise.allSettled => ", res); }); console.log(`end`); // start // end // MyPromise.allSettled => [ // { status: '成功', value: 1 }, // { status: '成功', value: undefined }, // { status: '失败', reason: 3 } // ]

.allSettled()函数完整代码:

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } catch(error) { return this.then(null, error); } finally(callback) { return this.then(callback, callback); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } // 接收一个数组(Promise任务数组) static all(promiseLists) { // 如果不是数组,则返回报错 if (Array.isArray(promiseLists)) { // 判断边界。当数组为空时,返回Promise对象的空数组 //(目的是在.then的参数的回调中能接收到此值) if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } // 返回一个Promise对象,内容是正确时的数组、或失败时的信息, // 所以我们resolve回调函数中存放返回的成功的数组, // reject回调函数接收错误信息 return new MyPromise((resolve, reject) => { //当前执行第几个 let count = 0; // 存放执行完成后的结果(成功结果) let resList = []; // 此步骤循环执行promiseLists中的Promise for (let i = 0; i < promiseLists.length; i++) { // 判断当前是不是Promise对象,如果不是,我们就直接返回此数据就好 if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = res; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); // 如果失败,直接返回当前失败信息 }, (err) => { reject(err); } ); } else { console.log("普通数据类型", promiseLists[i]); //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = promiseLists[i]; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } static allSettled(promiseLists) { if (Array.isArray(promiseLists)) { if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } return new MyPromise((resolve, reject) => { let count = 0; let resList = []; for (let i = 0; i < promiseLists.length; i++) { if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { count++; // 1、改造此处,加入状态和返回值即可 resList[i] = { status: MyPromise.FULFILLED, value: res, }; count === promiseLists.length && resolve(resList); }, (err) => { count++; // 3、改造此处(错误信息),加入状态和返回值即可 resList[i] = { status: MyPromise.REJECTED, reason: err, }; count === promiseLists.length && resolve(resList); } ); } else { count++; // 2、改造此处,加入状态和返回值即可 resList[i] = { status: MyPromise.FULFILLED, value: promiseLists[i], }; count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } }

实现.race函数

说明:Promise任务列表之中有一个实例率先改变状态,Promise的状态就跟着改变。那个率先改变的 Promise 实例的返回值。

先看原版例子:

js
// 情况一:两个Promise任务,一起执行,成功的优先执行 let p1 = new Promise((resolve,reject)=>{ setTimeout(()=>{resolve('p1成功了')},2000) }) let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{reject('p2失败了')},3000) }) Promise.race([p1,p2]).then(res=>{ console.log('then-res:',res) //日志输出:then-res: p1成功了 },err=>{ console.log('then-err:',err) }) // 情况二:两个Promise任务,一起执行,失败的优先执行 let p1 = new Promise((resolve,reject)=>{ setTimeout(()=>{resolve('p1成功了')},2000) }) let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{reject('p2失败了')},1000) }) Promise.race([p1,p2]).then(res=>{ console.log('then-res:',res) },err=>{ console.log('then-err:',err) //日志输出:then-err: p2失败了 })

so 看懂了。。。接下来我们改造⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.race static race(promiseLists){ return new MyPromise((resolve, reject) => { for (let i = 0; i < promiseLists.length; i++) { // 循环任务列表,全部都执行,当其中有一个执行完成了,直接返回结果 // 类似兔子赛跑,看哪个先执行完(不管成功或失败) MyPromise.resolve(promiseLists[i]).then( (res) => { resolve(res); }, (err) => { reject(err); } ); } }); } }

验证:

js
// 情况一:两个Promise任务,一起执行,成功的优先执行 let p1 = new MyPromise((resolve,reject)=>{ setTimeout(()=>{resolve('p1成功了')},2000) }) let p2 = new MyPromise((resolve,reject)=>{ setTimeout(()=>{reject('p2失败了')},3000) }) MyPromise.race([p1,p2]).then(res=>{ console.log('then-res:',res) //日志输出:then-res: p1成功了 },err=>{ console.log('then-err:',err) }) // 情况二:两个Promise任务,一起执行,失败的优先执行 let p1 = new MyPromise((resolve,reject)=>{ setTimeout(()=>{resolve('p1成功了')},2000) }) let p2 = new MyPromise((resolve,reject)=>{ setTimeout(()=>{reject('p2失败了')},1000) }) MyPromise.race([p1,p2]).then(res=>{ console.log('then-res:',res) },err=>{ console.log('then-err:',err) //日志输出:then-err: p2失败了 })

so 这是我们想要的结果。撒花了嘛?不,我们还有边界情况。。。先跑一下源码(传入空数组的情况)

image.png

so 继续改造⬇️

js
class MyPromise{ ... // 忽略上方逻辑,只关注如何实现.race static race(promiseLists){ return new MyPromise((resolve, reject) => { // 当数组没有任务时,不操作resolve和reject可实现一直pending状态 if(promiseLists.length>0){ for (let i = 0; i < promiseLists.length; i++) { MyPromise.resolve(promiseLists[i]).then( (res) => { resolve(res); }, (err) => { reject(err); } ); } } }); } }

验证:

js
MyPromise.race([]).then(res=>{ console.log('then-res:',res) },err=>{ console.log('then-err:',err) }) // 没有结果,一致pending状态

so 完整race代码和其他代码整合:

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } catch(error) { return this.then(null, error); } finally(callback) { return this.then(callback, callback); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } // 接收一个数组(Promise任务数组) static all(promiseLists) { // 如果不是数组,则返回报错 if (Array.isArray(promiseLists)) { // 判断边界。当数组为空时,返回Promise对象的空数组 //(目的是在.then的参数的回调中能接收到此值) if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } // 返回一个Promise对象,内容是正确时的数组、或失败时的信息, // 所以我们resolve回调函数中存放返回的成功的数组, // reject回调函数接收错误信息 return new MyPromise((resolve, reject) => { //当前执行第几个 let count = 0; // 存放执行完成后的结果(成功结果) let resList = []; // 此步骤循环执行promiseLists中的Promise for (let i = 0; i < promiseLists.length; i++) { // 判断当前是不是Promise对象,如果不是,我们就直接返回此数据就好 if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = res; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); // 如果失败,直接返回当前失败信息 }, (err) => { reject(err); } ); } else { console.log("普通数据类型", promiseLists[i]); //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = promiseLists[i]; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } static allSettled(promiseLists) { if (Array.isArray(promiseLists)) { if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } return new MyPromise((resolve, reject) => { let count = 0; let resList = []; for (let i = 0; i < promiseLists.length; i++) { if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { count++; // 1、改造此处,加入状态和返回值即可 resList[i] = { status: MyPromise.FULFILLED, value: res, }; count === promiseLists.length && resolve(resList); }, (err) => { count++; // 3、改造此处(错误信息),加入状态和返回值即可 resList[i] = { status: MyPromise.REJECTED, reason: err, }; count === promiseLists.length && resolve(resList); } ); } else { count++; // 2、改造此处,加入状态和返回值即可 resList[i] = { status: MyPromise.FULFILLED, value: promiseLists[i], }; count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } static race(promiseLists) { return new MyPromise((resolve, reject) => { // 当数组没有任务时,不操作resolve和reject可实现一直pending状态 if (promiseLists.length > 0) { for (let i = 0; i < promiseLists.length; i++) { MyPromise.resolve(promiseLists[i]).then( (res) => { resolve(res); }, (err) => { reject(err); } ); } } }); } }

race函数撒花🎉

实现any函数

说明:只要有一个Promise为成功,就会这个成功Promise的结果,如果所有Promise为失败,那么最终新Promise的状态为rejected且报错

js
class MyPromise{ ... // static any(promiseLists){ if (Array.isArray(promiseLists)) { return new MyPromise((resolve, reject) => { let count = 0; let errors = []; // 注意注意:如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise。 if (promiseLists.length === 0) { reject(new AggregateError("All promises were rejected")); } promiseLists.forEach((item, index) => { MyPromise.resolve(item).then( (res) => { resolve(res); }, (reason) => { count++; errors.push(reason); /** * 如果可迭代对象中没有一个 promise 成功,就返回一个失败的 promise 和AggregateError类型的实例, * AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。 */ count === promiseList.length && reject(new AggregateError(errors)); } ); }); }); } else { throw TypeError("argument must be Array"); } } }

最终代码

js
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; currentStatus = null; currentRes = null; asyncFulfillList = []; asyncRejectList = []; constructor(func) { this.currentStatus = MyPromise.PENDING; try { func(this.resolve.bind(this), this.reject.bind(this)); } catch (err) { this.reject(err); } } resolve(res) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.FULFILLED; this.currentRes = res; for (const callback of this.asyncFulfillList) { callback(); } } } reject(rej) { if (this.currentStatus === MyPromise.PENDING) { this.currentStatus = MyPromise.REJECTED; this.currentRes = rej; for (const callback of this.asyncRejectList) { callback(); } } } then(onFulfilleder, onRejecteder) { onFulfilleder = typeof onFulfilleder === "function" ? onFulfilleder : (val) => val; onRejecteder = typeof onRejecteder === "function" ? onRejecteder : (err) => err; return new MyPromise((resolve, reject) => { if (this.currentStatus === MyPromise.PENDING) { this.asyncFulfillList.push(() => { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); }); this.asyncRejectList.push(() => { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); }); } if (this.currentStatus === MyPromise.FULFILLED) { setTimeout(() => { let x = onFulfilleder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : resolve(x); }); } else if (this.currentStatus === MyPromise.REJECTED) { setTimeout(() => { let x = onRejecteder(this.currentRes); x instanceof MyPromise ? x.then(resolve, reject) : reject(x); }); } }); } catch(error) { return this.then(null, error); } finally(callback) { return this.then(callback, callback); } static resolve(value) { if (value instanceof MyPromise) { return value; } else if ( value && typeof value === "object" && value.hasOwnProperty("then") ) { return new MyPromise((resolve, reject) => { value.then(resolve, reject); }); } return new MyPromise((resolve, reject) => { resolve(value); }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } // 接收一个数组(Promise任务数组) static all(promiseLists) { // 如果不是数组,则返回报错 if (Array.isArray(promiseLists)) { // 判断边界。当数组为空时,返回Promise对象的空数组 //(目的是在.then的参数的回调中能接收到此值) if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } // 返回一个Promise对象,内容是正确时的数组、或失败时的信息, // 所以我们resolve回调函数中存放返回的成功的数组, // reject回调函数接收错误信息 return new MyPromise((resolve, reject) => { //当前执行第几个 let count = 0; // 存放执行完成后的结果(成功结果) let resList = []; // 此步骤循环执行promiseLists中的Promise for (let i = 0; i < promiseLists.length; i++) { // 判断当前是不是Promise对象,如果不是,我们就直接返回此数据就好 if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = res; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); // 如果失败,直接返回当前失败信息 }, (err) => { reject(err); } ); } else { console.log("普通数据类型", promiseLists[i]); //执行完就把状态累计加1 count++; // 不能用push。我们要保证按顺序执行和接收 resList[i] = promiseLists[i]; // 判断,如果累计计数等于数组长度了,说明都成功了。就可以返回成功的数据了 count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } static allSettled(promiseLists) { if (Array.isArray(promiseLists)) { if (promiseLists.length === 0) { return new MyPromise((resolve, reject) => { resolve(promiseLists); }); } return new MyPromise((resolve, reject) => { let count = 0; let resList = []; for (let i = 0; i < promiseLists.length; i++) { if (promiseLists[i] instanceof MyPromise) { MyPromise.resolve(promiseLists[i]).then( (res) => { count++; // 1、改造此处,加入状态和返回值即可 resList[i] = { status: MyPromise.FULFILLED, value: res, }; count === promiseLists.length && resolve(resList); }, (err) => { count++; // 3、改造此处(错误信息),加入状态和返回值即可 resList[i] = { status: MyPromise.REJECTED, reason: err, }; count === promiseLists.length && resolve(resList); } ); } else { count++; // 2、改造此处,加入状态和返回值即可 resList[i] = { status: MyPromise.FULFILLED, value: promiseLists[i], }; count === promiseLists.length && resolve(resList); } } }); } else { throw Error("当前all接收参数不是数组格式"); } } static race(promiseLists) { return new MyPromise((resolve, reject) => { // 当数组没有任务时,不操作resolve和reject可实现一直pending状态 if (promiseLists.length > 0) { for (let i = 0; i < promiseLists.length; i++) { MyPromise.resolve(promiseLists[i]).then( (res) => { resolve(res); }, (err) => { reject(err); } ); } } }); } static any(promiseList) { if (Array.isArray(promiseList)) { return new MyPromise((resolve, reject) => { let count = 0; let errors = []; // 注意注意:如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise。 if (promiseList.length === 0) { reject(new AggregateError("All promises were rejected")); } promiseList.forEach((item, index) => { MyPromise.resolve(item).then( (res) => { resolve(res); }, (reason) => { count++; errors.push(reason); /** * 如果可迭代对象中没有一个 promise 成功,就返回一个失败的 promise 和AggregateError类型的实例, * AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。 */ count === promiseList.length && reject(new AggregateError(errors)); } ); }); }); } else { throw TypeError("argument must be Array"); } } }
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:姚文罡

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!