一、promise出现的原因

在promise出现以前,我们处理多个异步请求,代码大概如下:

  1. 请求1(function(请求结果1){
  2. 请求2(function(请求结果2){
  3. 请求3(function(请求结果3){
  4. 请求4(function(请求结果4){
  5. 请求5(function(请求结果5){
  6. 请求6(function(请求结果3){
  7. ...
  8. })
  9. })
  10. })
  11. })
  12. })
  13. })

这便是臭名昭著的回调地狱,我们需要根据第一个网络请求结果,再去执行第二个网络请求,还要对每次请求的结果进行一些处理,代码会更加臃肿,在一个团队中,代码review以及后续的维护将会是一个痛苦的过程。
回调地狱带来的负面作用有以下几点:

  1. 代码臃肿。
  2. 可读性差。
  3. 耦合度过高,可维护性差。
  4. 代码复用性差。
  5. 容易滋生 bug
  6. 只能在回调里处理异常。

出现了问题,自然就会有人去想办法。这时候,就有人思考,能不能用一种更加友好的代码组织方式,解决异步嵌套的问题。

  1. let 请求结果1 = 请求1();
  2. let 请求结果2 = 请求2(请求结果1);
  3. let 请求结果3 = 请求3(请求结果2);
  4. let 请求结果4 = 请求4(请求结果3);
  5. let 请求结果5 = 请求5(请求结果4);

类似上面这种异步的写法,于是promise规范诞生了

二、什么是Promise

Promise是异步编程的一种解决方案,我们使用promise的时候会将函数的状态凝固,,比传统的异步解决方案(回调函数和事件)更合理,现已被es6纳入规范中。

Promise书写格式

对于上面的网络请求,Promise的常规写法:

  1. new Promise(请求1)
  2. .then(请求2(请求结果1))
  3. .then(请求3(请求结果2))
  4. .then(请求4(请求结果3))
  5. .then(请求5(请求结果4))
  6. .catch(处理异常(异常信息))

三、promise的api

resolve和reject

  1. const promise = new Promise(function(resolve, reject) {
  2. // ... some code
  3. if (/* 异步操作成功 */){
  4. resolve(value);
  5. } else {
  6. reject(error);
  7. }
  8. });

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”,在异步操作失败时调用,并将操作失败操作报出的错误,作为参数传递出去。

then和catch

  1. var p = new Promise((resolve,reject)=>{
  2. resolve("success");
  3. reject("fail")
  4. })
  5. p.then(res=>{
  6. console.log(res);//成功,输出success
  7. }).catch(err=>{
  8. console.log(err);//失败,输出fail
  9. })

then触发的是resolve的状态,即成功时的状态
catch触发的是reject的状态,即失败时的反馈

四、promise封装ajax请求

  1. function http(){
  2. return new Promise((resolve,reject)=>{
  3. $.ajax({
  4. url:"https://music.aityp.com/top/playlist?cat=华语",
  5. type:"get",
  6. success:res=>{
  7. resolve(res)
  8. },
  9. error:err=>{
  10. reject(err)
  11. }
  12. })
  13. })
  14. }
  15. http().then(res=>{
  16. console.log(res.data.playlists);
  17. })

五、Promise一些static方法

5-1 Promise.all

参考链接:理解和使用Promise.all和Promise.race

  1. const p = Promise.all([p1, p2, p3])

只有p1,p2,p3三个状态都是fulfilled的时候,p的状态才会是fulfilled。其中有一个rejected,p的状态就会变成rejected。下面是使用实例
code.png
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前(即使p1的结果获取的比p2要晚)。这带来一个很大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取的使用数据的场景,使用Promise.all可以很好解决这个问题。
code.png

5-2 Promise.race

code.png
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。