这里不过多的赘述promise是什么,既然点开此文章,就代表你对js已经很熟练使用了。所以,接下来给我一点时间,让我在这详细分步骤的手写promise核心区域,并且包括一些边界情况。
包括:如等待行异步?状态之间的关系?链式操作?
jsconst pro = new Promise((resolve,reject)=>{
resolve('成功')
reject('失败')
})
以上就是一个简单的Promise案例,其中resolve
表示成功后的回调函数,reject
表示失败后的回调函数。
手写Promise必须要明白他内部怎么回事,Promise本身会有三个状态,分别是"等待(PENDING)"
,"成功(FULFILLED)"
,"失败(REJECTED)"
。其中默认Promise的状态为“等待”,状态变化只能是“成功”、“失败”,只要状态一发生变化,后续就不可逆,不可再更改状态(可以理解:你打开王者荣耀,随机进了一局排位赛,比赛结果只有输赢,并且当前输赢已定局不能更改)。
绘图说明:
jsclass MyPromise{
constructor(func){
func(resolve,reject)
}
}
通过上方草率的写出了个Class,发现个问题:resolve
和reject
需要怎么写呢?应该写在哪里呢?
resolve
和reject
处理函数首先需要知道,resolve和reject函数,是在constructor构造函数内调用,所以,我们需要手写在当前自定义的Promise内定义这两个方法:
jsclass MyPromise{
constructor(func){
func(resolve,reject)
}
// 处理Promise回调函数中成功的逻辑
resolve(){}
// 处理Promise回调函数中错误、失败的逻辑
reject(){}
}
此时我们定义好对应的状态处理函数,在看,是不是constructor的func的参数,怎么调用呢?这时候,我们需要使用关键字“this”来指向这个函数
jsclass MyPromise{
constructor(func){
// 使用this指向我们的处理函数
func(this.resolve,this.reject)
}
// 处理Promise回调函数中成功的逻辑
resolve(){}
// 处理Promise回调函数中错误、失败的逻辑
reject(){}
}
完善Promise的状态。"等待(PENDING)"
,"成功(FULFILLED)"
,"失败(REJECTED)"
,有个疑问,这几个状态我们应该在代码中怎么个展示形式?是放在一个对象里?是放在这个类的属性里?还是放在静态资源里?
我选择放在静态资源中,如果放在this.status = {x:1,y:2,z:3}是不是又多创建个对象?是吧
jsclass MyPromise{
// 所以,我把状态写在静态资源中
static PENDING ='等待';
static FULFILLED ='成功';
static REJECTED ='失败';
constructor(func){
func(this.resolve,this.reject)
}
resolve(){}
reject(){}
}
Promise第一次初始化时,会有一个保存当前状态的一个值,这个值被本class共享使用,只有通过resolve或reject回调函数才会更改状态。so 下面补充下代码
jsclass MyPromise{
static PENDING ='等待';
static FULFILLED ='成功';
static REJECTED ='失败';
// 当前状态(这个值被本class共享使用)
currentStatus = null;
constructor(func){
// 初始化时,第一件事就是改变下状态
this.currentStatus = MyPromise.PENDING; // 等待状态
func(this.resolve,this.reject)
}
resolve(){}
reject(){}
}
在resolve
和reject
函数中,改变对应的状态。在看下我们使用这两个函数时,会有参数
带入是吧,思考,传递过来的参数,我们会在.then
的时候给返回出去,应该这个参数放到哪里呢?所以我们继续补充完整。
jsclass 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的状态只能更改一次,所以,我们需要更严谨的控制resolve
和reject
回调函数中的逻辑。
jsclass 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是怎么写的呢?它接收几个参数?每个参数什么作用?
答:两个参数、第一个参数是reslove的成功状态的回调,第二个是reject失败状态后回调。
原版这样写:
jsconst pro = new Promise((resolve,reject)=>{
resolve('成功了')
reject('失败了')
})
pro.then(
(res)=>{
console.log('.then成功时候拿到的值',res)
},
(err)=>{
console.log('.then失败后拿到的值',err)
}
)
so 我们完善.then的方法。
要考虑几点问题,.then是做什么的?参数怎么写?返回什么东西?
so 一步一步来
jsclass 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 我来简化下代码,去除注释,添加打印日志,我们试试
jsclass 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)
})
啪。。。。打脸(我诚心的,让你们分析原因)
TypeError:无法读取未定义的属性(读取“currentStatus”)
分析分析吧,是不是哪块有问题呢?我们分别在关键位置上打上日志(读取或设置currentStatus的地方),因为都是this调用currentStatus, so 我们关注this,看看哪里出问题了----逐步分析下,此时带日志的代码如下
jsclass 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)
})
日志反馈结果:
不卖关子了。重点在constructor的func
上的参数。
弄清----原因:首先,考虑具体是在哪里调用的这个func?弄明白之后你就知道了。
原因:外部调用MyPromise内部函数,并且没有任何指向关系。so,知道怎么做了吧
问题代码↓
JS...
constructor(func){
....
// 将被调用的函数this上下文指向当前MyPromise上解决问题
func(this.resolve.bind(this),this.reject.bind(this))
}
好了,我们完善下代码
JSclass 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)
})
舒服的执行完了
假设,我们写的Promise里有报错,我们怎么处理呢?
jsconst 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)
})
报错如图:
思考捕获时机:因为是在
func
函数内出现的报错。我们可以针对执行func
时进行try catch
捕获错误并直接交给reject
回调函数返回。
so 代码优化如下↓
jsclass 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 安全了
思考:Promise如何捕获异步?先抛出答案:任务列表。下面会讲到。
先看原生执行顺序
代码:
jsconsole.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的执行顺序:
目前我们自己的 代码:
jsconsole.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的执行顺序:
代码:
jsclass 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");
执行顺序被优化了
先看原生执行顺序
代码:
jsconsole.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的执行顺序:
目前我们自己的 代码:
jsconsole.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的执行顺序:
进行改造
思考:为什么会丢掉resolve
函数?没执行吗?
排查: 我们针对resolve
函数和.then
函数,分别打印日志,输出当前状态。
jsclass 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
通过上方日志分析:所有方法都执行了。只是他.then
的时候直接拿到DENPING(等待)
状态。这不是我们所期望的。
具体改造过程:
1、定义成功任务队列和失败任务队列。
2、将.then
状态为DENPING(等待)
时候,分别将处理函数放入对应任务队列中
3、在执行resolve
或reject
时,从任务队列中取出并全部执行。
代码如下:
jsclass 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毫米,并加上时间戳,方便查看差异。我们来试试执行
核心就是如何捕获异步、状态的派发及捕获、链式.then
jsclass 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);
})
}
})
}
}
先看下正常Promise是如何书写,在思考需准备什么
jsconst pro = Promise.resolve('123')
// 等同于这样书写
const pro = new Promise((resolve)=>{
resolve('123')
})
pro.then(res=>{
console.log('成功了', res)
})
思考🤔:
目测肯定返回一个Promise。
构造函数的方法,没有被实例,放在此类的静态资源上。
嗯对。so我们来写一下⬇️
jsclass MyPromise{
... // 忽略上方逻辑,只关注如何实现.resolve
static resolve(value){
return new MyPromise((resolve,reject)=>{
resolve(value)
})
}
}
丐中丐版本已实现⬆️
我们来处理一些边界情况
显然,这不是我们需要的结果res: MyPromise{...}
改造!⬇️
jsclass MyPromise{
... // 忽略上方逻辑,只关注如何实现.resolve
static resolve(value){
// 当前值如果就是一个MyPromise的值,就直接返回
if(value instanceof MyPromise){
return value
}
return new MyPromise((resolve,reject)=>{
resolve(value)
})
}
}
完美!不不不,还有问题
什么是thenable? 它是一个对象,并且带有then方法的对象 如下⬇️
jslet thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
文档的意思是,Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。 具体请看阮一峰Promise文章
so 处理下
jsclass 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)
})
}
}
执行完成结果:
通常,没有参数时,只是我们想让他变成一个微任务,在.then中执行一些延时逻辑
比如vue中$nextTick源码就使用到,Promise.resolve().then(callback)
我们什么都不做,跑一下代码试试,看看是不是异步的
jsconsole.log("start");
const pro = MyPromise.resolve();
console.log(`pro:`, pro);
pro.then((res) => {
console.log(`res:`, res);
});
console.log(`end`);
此时,resolve方法宣告完美😍
完成resolve函数的整体代码:
jsclass 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);
});
}
}
先看下正常Promise是如何书写,在思考需准备什么
jsconst pro = Promise.reject('出错了');
// 等同于
const pro = new Promise((resolve, reject) => reject('出错了'))
pro.then(null, function (s) {
console.log(s)// 出错了
});
so 我们应该只关注reject的结果是什么
Promise.reject()
方法返回一个带有拒绝原因的Promise对象
。
直接实现⬇️
jsclass MyPromise{
... // 忽略上方逻辑,只关注如何实现.reject
static reject(value){
return new MyPromise((resolve,reject)=>{
reject(value)
})
}
}
直接看结果:
so 带有reject函数的整体代码:
jsclass 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);
});
}
}
Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
思考🤔:这属于类上面的方法,不是静态资源了,是通过实例化才能得到的方法。
so 很简单⬇️
jsclass MyPromise{
... // 忽略上方逻辑,只关注如何实现.catch
catch(error){
return this.then(null,error);
}
}
验证一下:
so 带有
catch
函数的整体代码:
jsclass 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);
});
}
}
finally()
方法返回一个Promise
。在promise结束时,无论结果是fulfilled
或者是rejected
,都会执行指定的回调函数。
注意⚠️:次函数不接受任何参数。只表示promise执行完了而已。
so 怎么写呢⬇️
jsclass MyPromise{
... // 忽略上方逻辑,只关注如何实现.finally
finally(callback){
return this.then(callback,callback);
}
}
验证一下:
so 带有finally
函数的整体代码:
jsclass 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.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
原版写法:
jsconsole.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 我们尝试实现一下⬇️
jsclass 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接收参数不是数组格式')
}
}
}
看起来整体核心写完了。实际跑一下⬇️
全部都是成功时的情况
jsconsole.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 ]
部分成功的情况
jsconsole.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
如果当数组是个空数组呢
jsconsole.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
后的逻辑。我们补充完整(数组为空,返回成功的状态,并且也返回该数组)
jsclass 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 []
当我们promiseLists
参数重,有部分是普通数据,我们就不需要让他在经过包装Promise对象了,因为不需要多此一举。
so 代码改造如下⬇️
jsclass 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 我们验证下
jsconsole.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()
方法完结✅
附此步骤下的所有代码:
jsclass 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()
与.all()
函数
相同点包括:
不同的地儿包括:
so 直接改造.all()
函数即可(缝缝补补)代码如下⬇️
jsclass 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接收参数不是数组格式");
}
}
}
验证
jsconsole.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()
函数完整代码:
jsclass 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接收参数不是数组格式");
}
}
}
说明: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 看懂了。。。接下来我们改造⬇️
jsclass 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 这是我们想要的结果。撒花了嘛?不,我们还有边界情况。。。先跑一下源码(传入空数组的情况)
so 继续改造⬇️
jsclass 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);
}
);
}
}
});
}
}
验证:
jsMyPromise.race([]).then(res=>{
console.log('then-res:',res)
},err=>{
console.log('then-err:',err)
})
// 没有结果,一致pending状态
so 完整race代码和其他代码整合:
jsclass 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函数撒花🎉
说明:只要有一个Promise为成功,就会这个成功Promise的结果,如果所有Promise为失败,那么最终新Promise的状态为rejected且报错
jsclass 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");
}
}
}
jsclass 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");
}
}
}
本文作者:姚文罡
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!