学习Promise

一、Promise

1.异步任务的处理

在ES6出来之后,有很多关于Promise的讲解、文章,也有很多经典的书籍讲解Promise.

  • 虽然等你学会了Promise之后,会觉得Promise不过如此,但是在初次接触的时候都会觉得这个东西不好理解。

那么这里我从几个实际的例子来作为切入点:

  • 我们调用一个函数,这个函数中发送网络请求(我们可以用定时器来模拟)
  • 如果发送网络请求成功了,那么告知调用者发送成功,并且将相关数据返回过去。
  • 如果发送网络请求失败了,那么告知调用者发送失败,并且告知错误信息。

【任何一个新技术的出来,就是用来解决原有技术的某一个痛点】

//request.js
function requestData(url){
  // 模拟网络请求
  setTimeout(()=>{
    //拿到请求的1结果
    //url传入的是 coderwhy,请求成功
    if(url==="coderwhy"){
        let names=["wjy","hyz","tqy"];

        return names;//* 但其实这个return外面是拿不到结果的
    }else{// 否则请求失败
      let errMessage="请求失败,url错误";

      return errMessage;//* 但其实这个return外面是拿不到结果的
    }
    
  },3000)
}

// main.js
requestData("coderwhy")

修改requestData参数,需要传入成功的回调函数successCallback和失败的回调函数failCallback。

//request.js
function requestData(url,successCallback,failCallback){
  // 模拟网络请求
  setTimeout(()=>{
    //拿到请求的1结果
    //url传入的是 coderwhy,请求成功
    if(url==="coderwhy"){
        let names=["wjy","hyz","tqy"];
        successCallback(names);
    }else{// 否则请求失败
      let errMessage="请求失败,url错误";
      failCallback(errMessage)
    }
    
  },3000)
}

// main.js
requestData("coderwhy",(res)=>{
  console.log("成功:",res);
},(err)=>{
  console.log("失败:",err);
})

1.1 回调函数的弊端

  • 如果是我们自己封装的requestData,那么我们在封装的时候必须要自己设计好callback名称,并且使用好
  • 如果我们使用的是别人封装的requestData或者一些第三方库,那么我们必须去看别人的源码或者文档,才知道这个函数怎么去获取结果的。
  • 这种沟通成本非常多的

那么有没有一种更好的方式:

  • 那么有没有会返回一个承诺,这个承诺(规范了所有的代码编写逻辑)
// *  更好的方案 承诺(规范好了所有的代码编写逻辑)
function requestData2(){
  return "承诺"
}

const chengnuo=requestData2()

2.什么是Promise

Promise是ES6新增的一个API,它是一个类,可以翻译成 承诺、许诺、期约;

当我们需要给予调用者一个承诺:待会儿我会传给你回调数据时,就可以创建一个Promise对象

在通过new 创建Promise对象时,我们需要传入一个回调函数,我们称之为executor

  • 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject
  • 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数
  • 当我们调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数。
image-20220514142507394.png
function foo(){
  // Promise
  return new Promise((resolve,reject)=>{
    // resolve();
    reject();
  })
}

// main.js
const fooPromise=foo();

// * then方法传入的回调函数,会在Promise执行resolve函数时,会回调。
fooPromise.then(()=>{

})

// * catch方法传入的回调函数,会在Promise执行reject函数时,被回调
fooPromise.catch(()=>{

})

// class Person{
//   constructor(callback){
//     function foo(){

//     }
//     function bar(){

//     }
//     callback(foo,bar)
//   }
// }

// const p=new Person((foo,bar)=>{
//   foo();
//   bar()
// });

// * Promise是一个类,可以传入参数,参数是回调函数,这个回调函数在传入时,会立即被执行。
/**
 * * 传入的回调函数可以称之为 executor
 * * 这个回调函数会有两个参数:
 * * resolve :成功时,执行resolve回调
 * * reject:失败时,执行reject回调
 */
const promise=new Promise((resolve,reject)=>{
  // console.log("promise传入的函数立即被执行了");
  resolve();
})

promise.then(()=>{

})

promise.catch(()=>{
  
})
image-20220514144055335.png

2.1 异步处理的Promise方式

/**
 * * 回调的弊端
 * *   1.如果是我们自己封装的requestData,那么我们在封装的时候必须要自己设计好callback名称,并且使用好
* *    2.如果我们使用的是别人封装的requestData或者一些第三方库,那么我们必须去看别人的源码或者文档,才知道这个函数怎么去获取结果的。
* *    3.这种沟通成本非常多的
 */

//request.js
function requestData(url,successCallback,failCallback){
  // 模拟网络请求
  
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      //拿到请求的1结果
      //url传入的是 coderwhy,请求成功
      if(url==="coderwhy"){
          let names=["wjy","hyz","tqy"];
          resolve(names);
      }else{// 否则请求失败
        let errMessage="请求失败,url错误";
        reject(errMessage)
      }
      
    },3000);
  })
}



//main.js

const promise=requestData("coderwhy");

// * then方法传入两个回调函数
// * 第一个回调函数,会在Promise执行resolve函数时,被回调
// * 第二个回调函数,会在Promise执行reject函数时,被回调
promise.then((res)=>{
  console.log("请求成功:",res);
},(err)=>{
  console.log("请求失败了:",err);
})

3.Promise的三种状态

// 完全等价于下面的代码
new Promise((resolve,reject)=>{
  console.log("------------------");//* 阶段:pending 
  resolve();
}).then(res=>{
  console.log("res:",res);//* fulfilled(固定、已敲定)
},err=>{
  console.log("err:",err);//* rejected (已拒绝 )
})

上面的Promise使用过程,我们可以将它划分成三个状态:

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝

    • 当执行executor中的代码时,处于该状态。
  • 已兑现(fulfilled):意味着操作成功完成

    • 执行了resolved时,处于该状态
  • 已拒绝(rejected):意味着操作失败

    • 执行了reject 时,处于该状态

Promise状态一旦被确定下来,那么就是不可更改的(锁定),例如下面我们先执行了resolve,将状态改为 已兑现(fulfilled)。后面又执行了reject,企图将状态修改为已拒绝(rejected),但发现其实并不能进行修改的。

// * Promise状态一旦被确定下来,那么就是不可更改的(锁定)
new Promise((resolve,reject)=>{
  console.log("------------------");//* 阶段:pending 
  resolve();//* fulfilled(固定、已敲定)
  reject();////* rejected (已拒绝 ) ,这行代码没有任何意义。
  // resolve(123)
}).then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

4. resolve参数

  • 情况一:如果resolve传入一个普通的值或者对象,那么这个值就会作为then回调的参数
  • 情况二:如果resolve传入的是另外一个Promise,那么这个新Promise的状态会决定原Promise的状态
  • 情况三:如果resolve传入的是一个对象,并且这个对象有实现then方法,那么就会执行then方法,并且根据then方法的结果来决定Promise的状态。
/**
 * resolve(参数)
 * *  (1)普通的值或者对象
 * *  (2)传入一个Promise
 * *    那么当前的Promise状态由传入的Promise来决定
 * *    相当于状态进行了移交
 * *  (3)传入一个对象,并且这个对象有实现的then方法 (thenable),那么也会执行该then方法,并且由该then方法决定后续状态
 */

// * 传入Promise的特殊情况
// const newPromise=new Promise((resolve,reject)=>{
//   // resolve("aaaaa")
//   reject("err message")
// })
// new Promise((resolve,reject)=>{
//   resolve(newPromise)
// }).then(res=>{
//   console.log("res:",res);
// },err=>{
//   console.log("err:",err);
// })



//*  2.传入一个对象,这个对象有实现then方法,由该then方法决定后续状态
new Promise((resolve,reject)=>{

  const obj={
    then:function(resolve,reject){
      // resolve("resolve message");

      reject("reject message")
    }
  }
  resolve(obj);
}).then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
}) 

5.then方法

5.1 then方法-接受两个参数

then方法是Promise对象的一个方法,它其实是 放在Promise的原型上的Promise.prototype.then

then方法接受两个参数:

  • fulfilled的回调函数:当状态变成fulfilled时会回调的函数
  • rejected的回调函数:当状态变成rejected时会回调的函数
promise.then(res=>{
  console.log("res:",res);
},err=>{
 console.log("err:",err); 
})

// 等价于下面
promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

5.2 then方法-可以多次调用

同一个promise对象的then方法可以调用多次。

当resolve方法被回调时,所有传入到then方法的回调函数会执行。

// * Promise有哪些对象方法
// console.log(Promise.prototype);
// console.log(Object.getOwnPropertyDescriptors(Promise.prototype));

const promise=new Promise((resolve,reject)=>{
  resolve("hahahaha")
})

// *同一个promise可以多次调用then方法
// * 当我们的resolve方法被回调时,所有的then方法传入的回调函数都会被调用
promise.then((res)=>{
  console.log("res:",res);
})


promise.then((res)=>{
  console.log("res2:",res);
})

promise.then((res)=>{
  console.log("res3:",res);
})

5.3 then方法——返回值

其实then方法有返回值,返回的是新的Promise对象

then方法的回调函数也有返回值,当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数

  • 如果返回的是一个普通的值(数字、字符串、对象),这个值会作为then方法返回的Promise对象的resolve的值

    • 如果没有返回值,则默认返回的是undefined

      const promise=new Promise((resolve,reject)=>{
        resolve("hahahaha")
      })
      promise.then(res=>{
        // *如果回调函数没有返回值,则返回的是一个undefined
        return {name:"wjy"}
      }).then(res=>{
        console.log("res:",res);
      })
      
      
  • 如果返回的是一个Promise对象,

    • 这个返回的Promise对象会决定then方法返回的Promise的状态
    const promise=new Promise((resolve,reject)=>{
      resolve("hahahaha")
    })
    // *如果返回的是一个Promise对象
    promise.then(res=>{
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{
          resolve("hello wjy")
        },3000)
      })
    }).then(res=>{
      console.log("res:",res);
    })
    
    
  • 如果返回的是一个对象,这个对象实现了thenable(then方法),会立即执行then方法,并根据then方法的结果来决定Promise的状态。
// *如果返回了是一个对象,并且这个对象上
promise.then(res=>{  
  return {  //* new Promise(resolve=>resolve(obj.then))
    then:function(resolve,reject){
      resolve(2222)
    }
  } 
}).then(res=>{
  console.log("res:",res);
})

6.catch方法

then方法内部可以传入两个参数(两个回调函数)

  • 当resolve函数被执行时,会调用then方法的第一个参数(回调函数)

  • 当reject函数被执行时,会调用then方法的第二个参数(回调函数)【或者内部发生错误,也会被then方法的第二个参数捕获到。】

    • const promise=new Promise((resolve,reject)=>{
        reject("rejected status")
      })
      
      promise.then(undefined,err=>{
        console.log("err:",err);
      })
      
    • const promise=new Promise((resolve,reject)=>{
        throw new Error("rejected status")
      })
      
      promise.then(undefined,err=>{
        console.log("err:",err);
      })
      

如果将成功和失败的回调函数写在一块,阅读性差,比如下面:

const promise=new Promise((resolve,reject)=>{
  // reject("rejected status")
  throw new Error("rejected status")
})

promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

支持另外一种方法:

通过catch方法传入错误或拒绝的捕获的回调函数:

const promise=new Promise((resolve,reject)=>{
  reject("rejected status")
})


// * 通过catch方法传入错误或(拒绝)捕获的回调函数
// promise/a+规范
promise.catch(err=>{
  console.log("err:",err)
})

还支持另外一种写法:

  • catch会优先捕获第一个Promise对象的异常捕获,如果第一个Promise对象没有发生异常,则不会使用,会留着下一次使用。如果第二个Promise对象发生异常,这个catch会去捕获。
  • 这个catch方法比较特殊
const promise=new Promise((resolve,reject)=>{
  reject("rejected status")
  // throw new Error("rejected status")
})


promise.then(res=>{
  return 111
}).catch(err=>{
     console.log("err:",err)
})

image-20220514193022157.png
const promise=new Promise((resolve,reject)=>{
  resolve("resolve status")
})


promise.then(res=>{
  throw new Error("发生错误")
  return 111
}).catch(err=>{
  console.log("err:",err);//*如果第一个promise对象没有异常,所以就不会执行,等着下一次使用,会给下一个Promise对象使用
  console.log("------");
})
image-20220514193638998.png

6.1 拒绝捕获的问题

// * 拒绝捕获的问题(前面课程)
const promise=new Promise((resolve,reject)=>{
  reject("rejected status");//* 有点类似抛出异常
})
promise.then(res=>{
  console.log("res:",res);
})

promise.catch(err=>{
  console.log("err:",err);
})

这个代码运行后会报错的。

image-20220514195146223.png
  • 之间不会相互影响的
  • 因为在then方法中没有进行捕获,以异常的方式退出。
  • 如果代码中没有then方法就不会报错

改成下面这种就不会报错:

// * 拒绝捕获的问题(前面课程)
const promise=new Promise((resolve,reject)=>{
  reject("rejected status");//* 有点类似抛出异常
})
promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

const promise=new Promise((resolve,reject)=>{
  reject("rejected status");//* 有点类似抛出异常
})
promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

6.2 reject和throw同时存在抛出哪个异常

如果执行了reject(),throw会被忽略

如果执行了throw,throw后面的代码都不会再执行。

6.3 catch方法多次调用

catch方法也是Promise对象上的一个方法,它也是放在Promise的原型上的Promise.prototype.catch方法。

同一个Promise对象的catch方法可以被调用多次

  • 每当调用我们可以传入对应的reject回调
  • 当Promise的状态变成rejected的时候,这些回调函数都会被执行。
const promise=new Promise((resolve,reject)=>{
  reject("aaa");
})

promise.catch(err=>{
  console.log("err1:",err);
})

promise.catch(err=>{
  console.log("err2:",err);
})

promise.catch(err=>{
  console.log("err3:",err);
})

6.4 catch方法——返回值

事实上catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法

 const promise=new Promise((resolve,reject)=>{
  reject("aaa");
})

promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
  return "catch return value"
}).then(res=>{
  console.log("res:",res);
})
const promise=new Promise((resolve,reject)=>{
  reject("aaa");
})
promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve("my name")
    },3000)
  })
}).then(res=>{
  console.log("res:",res);
})

7.fanally方法

fanally是ES9(ES2018)新增的一个特性:表示无论Promise的状态变为fulfilled还是reject状态,最终都会被执行的代码。

finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行。

const promise=new Promise((resolve,reject)=>{
  resolve("resolve message");
})

promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
}).finally(()=>{
  console.log("finally code execute");
})

finally其实也是返回一个Promise对象,但是其实很少人会用它

8.类方法——resolve方法

前面我们学习的then、catch、finally方法都属于Promise的实例方法,都是存放在Promise的prototype上的。

下面我们将学习类方法

有时候我们已经有一个现成的内容,希望将其转成Promise来使用,这个时候我们可以使用Promise.resolve方法来完成。

  • Promise.resolve()方法:相当于new Promise,并且执行resolve操作。

resolve的参数形式:

  • 情况一:参数是一个普通的值或者对象
  • 情况二:参数是一个Promise对象
  • 情况三:参数是一个thenable
function foo(){
  const obj={name:"wjy"}
  return new Promise((resolve)=>{
    resolve(obj);
  });
}

foo().then(res=>{
  console.log("res:",res);
})

等价于下面:

function foo(){
  const obj={name:"wjy"}
 return Promise.resolve(obj);
}

foo().then(res=>{
  console.log("res:",res);
})

8.1 参数形式

// * 1.传入普通的值
// const promise=Promise.resolve({name:"wjy"});

// * 2.传入一个Promise,由这个新的Promise对象决定原Promise对象的状态
// const promise=Promise.resolve(new Promise((resolve,reject)=>{
//   // resolve("resolve2 message")
//     reject("reject message")
// }))

// promise.then(res=>{
//   console.log("res:",res);
// }).catch(err=>{
//   console.log("err:",err);
// })

// * 3. 传入thenable对象(实现了then方法),会立即执行then方法,由then方法的结果决定其Promise的状态
const promise=Promise.resolve({
  then:function(resolve,reject){
    // resolve("resolve ");
    reject("reject message")
  }
})

promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

9.类方法——reject方法

reject方法类似于resolve方法,只是会将Promise对象的状态设置为rejected状态

Promise.reject的用法相当于new Promise,并且会调用reject

Promise.reject无论传过来的参数是什么状态,都会直接作为reject的参数传递到catch的。

10.类方法——all方法

它的作用是将多个Promise包裹在一起,形成一个新的Promise

新的Promise状态由包裹的所有Promise决定

  • 当所有的Promise状态变为fulfilled状态时,新的Promise状态为fulfilled,并且会将所有的Promise的返回值组成一个数组
  • 当有一个Promise状态变为rejected状态时,新的Promise状态为rejected,并且会将第一个reject的返回值作为参数
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})

// * 需求:所有的Promise都变成fulfilled,再拿到结果
//*  意外:在拿到所有结果之前,有一个promise变成了rejected,那么整个promise是rejected
Promise.all([p1,p2,p3,"aaaa"]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  // * 最后转到catch执行
  console.log("err:",err);
})

// * all:所有的promise为fulfilled时才会执行then方法,如果有一个状态为rejected,就会转成执行catch方法

11.类方法——allSettled方法

all方法有一个缺陷:当有一个Promise变成rejected状态时,新Promise就会立即变成对应的rejected状态。

  • 那么对于resolved的,以及仍然处于pending状态的Promise,我们是获取不到对应的结果的。

在ES11(ES2020)中,添加了新的API Promise.allSettled

  • 该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是rejected时,才会有最终的状态。
  • 并且这个Promise的结果一定是fulfilled的
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})


// allSettled
// * 新的Promise的状态一定是fulfilled
Promise.allSettled([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

12. 类方法——race

如果有一个Promise有了结果,我们就希望决定最终新的Promise的状态,那么可以使用race方法

  • race是竞技、竞赛的意思,表示多个Promise相互竞争,谁先有结果,那么就使用谁的结果。
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})


// * race :竞技 竞赛
Promise.race([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

13.类方法——any方法

any方法是ES12中新增的方法,和race方法是类似的:

  • any方法会等到一个fulfilled状态,才会决定新Promise的状态
  • 如果所有的Promise都是rejected的,那么也会等到所有的Promise都变成rejected状态。
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})


// * any
Promise.any([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  // *可以通过.errors拿到合计的错误信息
  console.log("err:",err.errors);
})
  • 如果所有的Promise都是reject的,那么会报一个AggregateError的错误。

二、手写Promise

1.Promise的设计和构造方法

const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";
// * 自己手写的Promise要符合的一定的规范,要符合PromiseA+
class HYPromise{
  // * 记录状态
  constructor(executor) {
    // * 保存Promise的状态
    this.status=PROMISE_STATUS_PENDING;
    // * 保存传入的值
    this.value=undefined;
    this.reason=undefined;
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_FULFILLED;
        this.value=value;
        console.log("resolve被调用");
      }
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        console.log("reject被调用");
      }
     
    }
    executor(resolve,reject)
  }
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("状态pending");
  resolve("1111")
})

2.then方法的设计

 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";
// * 自己手写的Promise要符合的一定的规范,要符合PromiseA+
class HYPromise{
  // * 记录状态
  constructor(executor) {
    // * 保存Promise的状态
    this.status=PROMISE_STATUS_PENDING;
    // * 保存传入的值
    this.value=undefined;
    this.reason=undefined;
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_FULFILLED;
        queueMicrotask(()=>{ //* 定时器是一个宏任务,会放在下一次事件循环时使用
        
          this.value=value;
          console.log("resolve被调用");
          // * 执行then传入进来的第一个回调函数
          this.onFulfilled(this.value)
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_REJECTED;
       queueMicrotask(()=>{
        this.reason=reason;
        console.log("reject被调用");
        // * 执行then传入进来的第二个回调函数
        this.onRejected(this.reason);
       })
      }
     
    }
    executor(resolve,reject)
  }
  then(onFulfilled,onRejected){
    this.onFulfilled=onFulfilled;
    this.onRejected=onRejected;
  }
 
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("状态pending");
  // resolve("1111")
  reject("reject message")
})

promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

promise.then(res=>{
  console.log("res2:",res);
},err=>{
  console.log("err2:",err);
})

// * 多次调用then,后面的then方法会覆盖前面的then方法,而且只会调用一次方法
// * then方法不能实现链式调用

3.then方法的优化一

  • 实现then多次调用
  • 如果Promise状态已经确定,再次调用then方法,传入的回调函数应该直接执行
 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";
// * 自己手写的Promise要符合的一定的规范,要符合PromiseA+
class HYPromise{
  // * 记录状态
  constructor(executor) {
    // * 保存Promise的状态
    this.status=PROMISE_STATUS_PENDING;
    // * 保存传入的值
    this.value=undefined;
    this.reason=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        queueMicrotask(()=>{ //* 定时器是一个宏任务,会放在下一次事件循环时使用
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          console.log("resolve被调用");
          // * 执行then传入进来的第一个回调函数
         this.onFulfilledFns.forEach(Fn=>{
           Fn(this.value)
         })
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       
       queueMicrotask(()=>{ 
         this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        console.log("reject被调用");
        // * 执行then传入进来的第二个回调函数
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason)
        })
       })
      }
     
    }
    executor(resolve,reject)
  }
  then(onFulfilled,onRejected){
    // 1.如果then方法调用的时候,状态已经确定下来了,应该直接执行的
    if(this.status===PROMISE_STATUS_FULFILLED&&onFulfilled){
      onFulfilled(this.value);
    }else if(this.status===PROMISE_STATUS_REJECTED&&onRejected){
      onRejected(this.reason)
    }else{
      // 将成功回调和失败回调添加到数组中
    this.onFulfilledFns.push(onFulfilled);
    this.onRejectedFns.push(onRejected);
    }
    
  }
 
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("状态pending");
  resolve("1111");//resolved/fulfilled
})

promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

promise.then(res=>{
  console.log("res2:",res);
},err=>{
  console.log("err2:",err);
})



setTimeout(()=>{
  promise.then(res=>{
    console.log(res);
  })
},1000)

// * 解决了then方法的多次调用
// * 在确定Promise状态之后,再次调用then
// const promise2=new Promise((resolve,reject)=>{
//   resolve("aaaaa");
// })

// setTimeout(()=>{
//   promise2.then(res=>{ //原生编写了
//     console.log(res);
//   })
// },1000)

4.then方法的优化二

  • 实现了一个链式调用(返回一个新的Promise对象,使用新的Promise对象的resolve方法去处理对应的回调函数的返回值)
  • 实现了对executor执行时发生异常(错误),应该执行reject函数
  • 后面封装了一个工具函数,用来处理异常和回调
 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函数
function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    let result=exeFn(value);
    reject(result);
  }catch(err){
    reject(err);
  }
}
// * 自己手写的Promise要符合的一定的规范,要符合PromiseA+
class HYPromise{
  // * 记录状态
  constructor(executor) {
    // * 保存Promise的状态
    this.status=PROMISE_STATUS_PENDING;
    // * 保存传入的值
    this.value=undefined;
    this.reason=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 添加微任务
        queueMicrotask(()=>{ //* 定时器是一个宏任务,会放在下一次事件循环时使用
          if(this.status!==PROMISE_STATUS_PENDING) return;
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          // console.log("resolve被调用");
          // * 执行then传入进来的第一个回调函数
         this.onFulfilledFns.forEach(Fn=>{
           Fn(this.value);
         })
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
      //  * 添加微任务
       queueMicrotask(()=>{ 
         if(this.status!==PROMISE_STATUS_PENDING) return;
         this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // console.log("reject被调用");
        // * 执行then传入进来的第二个回调函数
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason)
        })
       })
      }
     
    }

    // * 在调用executor时判断里面是否抛出异常
    try{
      executor(resolve,reject)
    }catch(err){
      reject(err)
    }
  }
  then(onFulfilled,onRejected){
   
    return new HYPromise((resolve,reject)=>{
       // 1.如果then方法调用的时候,状态已经确定下来了,应该直接执行的
    if(this.status===PROMISE_STATUS_FULFILLED&&onFulfilled){
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    }else if(this.status===PROMISE_STATUS_REJECTED&&onRejected){
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
    }else{
      // 将成功回调和失败回调添加到数组中
    this.onFulfilledFns.push(()=>{
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    });
    this.onRejectedFns.push(()=>{
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
 });
    }
    })
  }
 
}

const promise=new HYPromise((resolve,reject)=>{
  // console.log("状态pending");
  // resolve("1111");//resolved/fulfilled
  reject("2222")
  // throw new Error("创建就报的异常")
})

promise.then(res=>{
  console.log("res:",res);
  return "aaaa"

},err=>{
  console.log("err:",err);
  return "err bbb"
}).then(res=>{
  console.log("res2:",res);
},err=>{
  console.log("err2:",err);
})

// * 1. 实现了链式调用,链式调用的前提是返回一个新的HYPromise,最重要的是 什么时候执行resolve,什么时候执行reject
// * 一般在正常情况下,无论原HYPromise的状态是如何,后面都会执行新的HYPromise的resolve,并将其值作为参数
// * 只有在代码发生异常时(错误),才会让新的HYPromise执行reject

// * 2. 在HYPromise的executor执行过程中如果发生异常,应该要执行reject


5.catch方法的设计

  • catch只会接受一个onRejected的回调函数
    • 在内部调用then方法,设置then方法的第一个参数为undefined,第二个参数的值为onRejected
  // * catch方法的设计
  catch(onRejected){
    this.then(undefined,onRejected);
  }

但是这样还是不能捕获原Promise对象的rejected状态,因为这个catch方法是针对新的Promise的rejected的状态,如果想要捕获原Promise的rejected状态,需要抛出异常,新的Promise对象的catch方法才能捕获到。

所以我们需要改写then方法:

  • 在方法内部前面判断第二个参数是否有值,如果没有值,就重新赋值为一个函数,函数内部抛出一个异常

这样在新的Promise就能捕获到原来的promise的rejected的状态

 then(onFulfilled,onRejected){
   onRejected=onRejected||(err=>{throw err})
    //以下代码省略...
  }

全部的代码如下:

 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函数
function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    let result=exeFn(value);
    reject(result);
  }catch(err){
    reject(err);
  }
}
// * 自己手写的Promise要符合的一定的规范,要符合PromiseA+
class HYPromise{
  // * 记录状态
  constructor(executor) {
    // * 保存Promise的状态
    this.status=PROMISE_STATUS_PENDING;
    // * 保存传入的值
    this.value=undefined;
    this.reason=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 添加微任务
        queueMicrotask(()=>{ //* 定时器是一个宏任务,会放在下一次事件循环时使用
          if(this.status!==PROMISE_STATUS_PENDING) return;
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          // console.log("resolve被调用");
          // * 执行then传入进来的第一个回调函数
         this.onFulfilledFns.forEach(Fn=>{
           Fn(this.value);
         })
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
      //  * 添加微任务
       queueMicrotask(()=>{ 
         if(this.status!==PROMISE_STATUS_PENDING) return;
         this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // console.log("reject被调用");
        // * 执行then传入进来的第二个回调函数
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason)
        })
       })
      }
     
    }

    // * 在调用executor时判断里面是否抛出异常
    try{
      executor(resolve,reject)
    }catch(err){
      reject(err)
    }
  }
  then(onFulfilled,onRejected){
   onRejected=onRejected||(err=>{throw err})
    return new HYPromise((resolve,reject)=>{
       // 1.如果then方法调用的时候,状态已经确定下来了,应该直接执行的
    if(this.status===PROMISE_STATUS_FULFILLED&&onFulfilled){
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    }else if(this.status===PROMISE_STATUS_REJECTED&&onRejected){
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
    }else{
      // 将成功回调和失败回调添加到数组中
    if(onFulfilled)this.onFulfilledFns.push(()=>{
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    });
    if(onRejected)this.onRejectedFns.push(()=>{
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
 });
    }
    })
  }
 
  // * catch方法的设计
  catch(onRejected){
    this.then(undefined,onRejected);
  }
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("状态pending");
  // resolve("1111");//resolved/fulfilled
  reject("2222")
  // throw new Error("创建就报的异常")
})


promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err1:",err);
}).catch(err=>{ 
  console.log("err:",err);
})

6.finally方法的设计

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函数

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生执行then方法时是一个微任务
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 执行then传入进来的回调函数
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 执行then传入进来的第二个参数
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("状态pending");
  // reject("111");
  resolve("222");
  // throw new Error("pending err")
  
})


promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("catch err:",err);
}).finally(()=>{
  console.log("finally方法实现");
})
// * 实现finally方法


7.类方法 resolve和reject的设计

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函数

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生执行then方法时是一个微任务
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 执行then传入进来的回调函数
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 执行then传入进来的第二个参数
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
  static resolve(value){
    return new HYPromise((resolve,reject)=>{
      resolve(value);
    })
  }
  static reject(reason){
    return new HYPromise((resolve,reject)=>{
      reject(reason);
    })
  }
}

HYPromise.resolve(123).then(res=>{
  console.log("res:",res);
})

HYPromise.reject("err message").catch(err=>{
  console.log("err:",err);
})


// * 实现了类方法 resolve和reject方法

 

8. 类方法 all 和allSettled

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函数

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生执行then方法时是一个微任务
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 执行then传入进来的回调函数
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 执行then传入进来的第二个参数
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
  static resolve(value){
    return new HYPromise((resolve,reject)=>{
      resolve(value);
    })
  }
  static reject(reason){
    return new HYPromise((resolve,reject)=>{
      reject(reason);
    })
  }
  static all(promises){
    // * 问题关键:什么时候执行resolve,什么时候执行reject
   return new HYPromise((resolve,reject)=>{
     let values=[];
      promises.forEach(promise=>{
        promise.then(res=>{
           values.push(res);
           if(values.length==promises.length) resolve(values);
        }).catch(err=>{
           reject(err);
        })
      })
   })
  }
  static allSettled(promises){
    
    return new Promise((resolve)=>{
      let results=[];
      promises.forEach(promise=>{
        promise.then(res=>{
          results.push({status:PROMISE_STATUS_FULFILLED,value:res})
          if(results.length==promises.length)
          resolve(results);
        }).catch(err=>{
          results.push({status:PROMISE_STATUS_REJECTED,value:err})
          if(results.length==promises.length)
          resolve(results);
        })
      })
    })
  }
}

const p1=new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})

const p2=new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(2222)
  },2000)
})

const p3=new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(3333)
  },3000)
})
// *all方法会产生一个新的Promise对象,这个新的Promise对象是由前面的所有的Promise来决定其状态
// * 如果全部为fulfilled,则会执行then方法,如果有一个为rejected,则直接执行catch方法
HYPromise.all([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})


// * allSettled:它会等所有的Promise都有结果,然后再执行resolve方法,它是没有reject方法的执行
// * 实现了all方法:

HYPromise.allSettled([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})
 

9. 类方法 race和any

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函数

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生执行then方法时是一个微任务
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 执行then传入进来的回调函数
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 执行then传入进来的第二个参数
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
  static resolve(value){
    return new HYPromise((resolve,reject)=>{
      resolve(value);
    })
  }
  static reject(reason){
    return new HYPromise((resolve,reject)=>{
      reject(reason);
    })
  }
  static all(promises){
    // * 问题关键:什么时候执行resolve,什么时候执行reject
   return new HYPromise((resolve,reject)=>{
     let values=[];
      promises.forEach(promise=>{
        promise.then(res=>{
           values.push(res);
           if(values.length==promises.length) resolve(values);
        }).catch(err=>{
           reject(err);
        })
      })
   })
  }
  static allSettled(promises){
    
    return new HYPromise((resolve)=>{
      let results=[];
      promises.forEach(promise=>{
        promise.then(res=>{
          results.push({status:PROMISE_STATUS_FULFILLED,value:res})
          if(results.length==promises.length)
          resolve(results);
        }).catch(err=>{
          results.push({status:PROMISE_STATUS_REJECTED,value:err})
          if(results.length==promises.length)
          resolve(results);
        })
      })
    })
  }

  static race(promises){
    return new HYPromise((resolve,reject)=>{
      promises.forEach(promise=>{
        // promise.then(res=>{
        //   resolve(res);
        // }).catch(err=>{
        //   reject(err);
        // })
        promise.then(resolve,reject)
      })
    })
  }
  static any(promises){
    // * resolve必须等待有一个成功的结果
    // * reject 所有的都失败才执行 reject
    return new HYPromise((resolve,reject)=>{
      let count=0;
      let reasons=[];
      promises.forEach(promise=>{
        promise.then(res=>{
          resolve(res)
        }).catch(err=>{
          reasons.push(err);
          if(reasons.length==promises.length){
            
            // reject(reasons)
            reject(new AggregateError(reasons," AggregateError: All promises were rejected"))
          }
        })
      })
    })
  }
}

// const p1=new Promise((resolve)=>{
//   setTimeout(()=>{
//     resolve(1111)
//   },1000)
// })

// const p2=new Promise((resolve)=>{
//   setTimeout(()=>{
//     resolve(2222)
//   },2000)
// })

// const p3=new Promise((resolve)=>{
//   setTimeout(()=>{
//     resolve(3333)
//   },3000)
// })

// HYPromise.race([p1,p2,p3]).then(res=>{
//   console.log("res:",res);
// }).catch(err=>{
//   console.log("err:",err);
// })

// * any方法
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(1111)
  },1000)
})

const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(2222)
  },2000)
})

const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(3333)
  },3000)
})

HYPromise.any([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err.errors);
})

三、总结

Promise.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容