重学JavaScript高级(十):十分钟掌握Promise细节

Promise–详解

ES5之前处理异步的方法

  • 会先封装一个工具函数
  • 接收三个参数,业务参数,成功回调函数,失败回调函数
  • 这种需要将成功以及失败的业务逻辑梳理清除,而且参数位置也没有规范
function tool(count, successCall, failCall) {
  setTimeout(() => {
    if (count > 0) {
      //填写业务逻辑
      successCall();
    } else {
      //填写业务逻辑
      failCall();
    }
  }, 2000);
}

tool(
  10,
  () => {
    //成功之后的业务逻辑
    console.log("执行成功");
  },
  () => {
    //失败之后的业务逻辑
    console.log("执行失败");
  }
);

引出Promise

  • Promise 是一个类,因此在使用的时候,需要new Promise
  • 通过 new Promise创建对象时候,我们需要在里面传递一个回调函数,称之为 executor
    • 这个回调函数会立即执行,并且传入另外两个回调函数 resolve reject
function tool(count) {
  //创建promise对象
  const promise = new Promise((resolve, reject) => {
    if (count > 0) {
      //成功时候执行resolve
      resolve("成功");
    } else {
      //失败时候执行reject
      reject("失败");
    }
  });
  //返回promise对象
  return promise;
}

tool(10)
  //.then接收resolve执行函数
  .then((res) => {
    console.log(res);
  })
  //.catch接收reject执行的函数
  .catch((err) => {
    console.log(err);
  });

Promise三个状态

pending(等待),fulfilled(成功)、rejected(已拒绝)

  • promise状态只会由 pending—>fufilled,或者 pending—>rejected这样转换,且转换之后的状态不会再切换
const promise = new Promise((resolve, reject) => {
  console.log(123);
  console.log(123);
  ///--以上都是pending状态
    
  resolve("123"); //转成了fulfilled状态
  resolve("adafaf");//只会执行一次改变状态的函数
    
  reject(); //不会执行reject
    
  console.log(123456); //但是后面的代码会执行
});
promise
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {});

  • fufilled状态
    • resolve函数中传递 普通值的时候:会直接返回值
    • resolve函数中传递 另一个Promise对象,则当前promise状态由传入的Promise来决定
    • resolve函数中传递 对象,且该对象中有then方法,则会执行该then方法,并且根据then方法的结果决定Promise的状态
//传递普通值
const promise1 = new Promise((resolve, reject) => {
  resolve("123");
});
promise1.then((res) => {
  console.log(res);
});

//传递另外一个promise
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(123);
  }, 2000);
});
const promise2 = new Promise((resolve, reject) => {
  resolve(p);
});
promise2.then((res) => {
  console.log(res);
});

//传递的对象中,有then方法
const promise3 = new Promise((resolve, reject) => {
  resolve({
    a: 100,
    //then中也要有resolve参数
    then(resolve, reject) {
      resolve(2222);
    },
  });
});
promise3.then((res) => {
  console.log(res);
});
  • rejected状态
const promise1 = new Promise((resolve, reject) => {
  reject("123");
});
promise1.then((res) => {
  console.log(res);
}).catch((err)=>{
    //使用catch接收
    console.log(err);
})

//若没有catch进行接收,则会报错
const promise1 = new Promise((resolve, reject) => {
  reject("123");
});
promise1.then((res) => {
  console.log(res);
});

image.png

Promise细节

实例方法—then的返回值

return的返回值,会让then方法中的promise处于fufilled状态,可以被后面的then接收到

throw new Error 会让then方法中的promise处于rejected状态,可以被后面最近的catch接收到

  • then方法的返回值是另外一个 Promise
const promise1 = new Promise((resolve, reject) => {
  reject("123");
});
promise1.then(res=>{
    console.log(res)
}).catch(err=>{
    //因为前面的then方法返回的是promise,所以后面可以接catch,进行链式调用
    console.log(err)
})

  • 如果多个then一起链式调用会怎么样
    • then内部会创建一个新的Promise,并会将then的返回值传入到新创建的Promise中的resolve中
    • 在执行then内部的函数过程中,新创建的Promise处于pending状态
    • 回调函数中return一个结果时候,新创建的Promise会处于fulfilled状态,并且将return的结果作为resolve的参数
      • 作为参数分为普通值、Promise、对象且含有then方法
const p = new Promise((resolve, reject) => {
  resolve(789);
});

const promise1 = new Promise((resolve, reject) => {
  resolve("123");
});
promise1

  .then((res) => {
    console.log(res);
    //返回一个普通值
    return 456;
  })

  //前一个then会创建一个新的Promise,并将return的内容,传递给新创建的Promise的reslove
  //所以这个then会接收到前一个then的return值
  .then((res) => {
    console.log(res); //
    //返回一个promise
    //相当于resolve(p),所以状态会由p决定
    return p;
  })

  .then((res) => {
    console.log(res); //789
    //return一个对象,该对象中由then方法
    return {
      then(resolve) {
        resolve("hahaha");
      },
    };
  })

  .then((res) => {
    console.log(res); //hahaha
  });

实例方法—catch的返回值

与then相同,返回值是promise对象

当catch中,return值时,新创建的promise处于fulfilled状态

当catch中,throw new Error值时,新创建的promise处于rejected状态

  • catch执行的时机
    • 当一个promise执行了reject函数
    • 就会将reject执行的结果,传给最近的catch
const promise1 = new Promise((resolve, reject) => {
  reject(123);
});

promise1
  .then((res) => {
    console.log(res);
    return 123;
  })
  .then((res) => {
    console.log(res);
  })
  .then((res) => {
    console.log(res);
  })
//这里的catch接收的不是前面then中promise的reject状态,而是接收的promise1的reject
  .catch((err) => {
    console.log(err);
  });

实例方法—finally方法

是在ES9中新增的特性,表示无论Promise对象无论是fulfilled还是rejected状态,都会执行该方法

  • finally中不接收参数
const promise1 = new Promise((resolve, reject) => {
  reject(123);
});

promise1
  .then((res) => {
    console.log(res);
    return 123;
  })
  .catch((err) => {
    console.log(err);
  })
  .finally(() => {
    console.log("我肯定会执行");
  });

类方法—resolve/reject

  • 正常使用
let count = 0
const promise1 = new Promise((resolve, reject) => {
  if(count === 0){
      //这就是类方法
      reject(123);
  }else{
      //这就是类方法
      resolve(456)
  }
});
  • resolve里面的值有三种情况(上面有介绍)

  • reject里面的值不分情况,都会作为reject状态参数,传递到catch中

  • 如果有一个已经存在的值,想直接返回fulfilled或者rejected状态,可以用以下写法

let obj = {a:100}//想将这个值转成promise的fulfilled状态
const p = Promise.resolve(obj)
p.then((res)=>{
    console.log(res)
})

//想把这个值转成rejected状态
const p1 = Promise.reject(obj)

p1.catch((err)=>{
    console.log(err)
})

类方法—all(多个promise联合使用)

传入多个Promise,将多个Promise包裹成一个新的Promise

  • 新的Promise的状态由多个Promise共同决定
    • 当多个Promise,共同为fulfilled状态的时候,新的Promise状态为fulfilled,并被then方法接收
    • 当其中一个出现reject,新的Promise状态为reject,并且会将第一个称为rejected状态的返回值作为参数,给catch方法,后面的promise根本不会执行
  • 下列全部的Promise全是fulfilled状态
const promise1 = new Promise((resolve, reject) => {
  resolve(123);
});

const promise2 = new Promise((resolve, reject) => {
  resolve(456);
});

const promise3 = new Promise((resolve, reject) => {
  resolve(789);
});

//all方法中传入的参数,必须是可迭代的(后续文章有奖可迭代对象)
Promise.all([promise1, promise2, promise3]).then((res) => {
  console.log(res); //[123,456,789],是一个数组形式,包含里面的所有Promise的返回值
});

  • 下列有一个或者两个为rejected状态
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(123);
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(456);
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  resolve(789);
});

//all方法中传入的参数,必须是可迭代的(后续文章有奖可迭代对象)
Promise.all([promise1, promise2, promise3])
  .then((res) => {
    console.log(res); //不会执行then中的方法
  })
  .catch((err) => {
    console.log(err);//456,因为promise2是最先为rejected状态的,同时promise1根本不会执行
  });

类方法—allSettled方法

上面我们知道,all方法存在一定的缺陷,因为只要有一个rejected状态,该状态后面的promise都不会执行

而allSettled解决了这个问题

  • allSettled会等待所有的Promise都有确定了状态,再返回
  • 无论是 reject状态还是fulfilled状态,都会返回到实例对象的then方法中
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(123);
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(456);
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  resolve(789);
});

//all方法中传入的参数,必须是可迭代的(后续文章有奖可迭代对象)
Promise.allSettled([promise1, promise2, promise3]).then((res) => {
  console.log(res); 
});
/**
[
  { status: 'rejected', reason: 123 },
  { status: 'rejected', reason: 456 },
  { status: 'fulfilled', value: 789 } 
]
 */

类方法—race方法

谁先有结果,就会使用谁的结果,不会等到所有的Promise都有结果

  • race不会在乎Promise状态,只要第一个确认了状态,就会返回
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(123);
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(456);
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  reject(789);
});

//all方法中传入的参数,必须是可迭代的(后续文章有奖可迭代对象)
Promise.race([promise1, promise2, promise3])
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err);//789
  });


类方法—any方法

与race方法不同,该方法会等待第一个fulfilled状态的Promise返回值

若都是rejected状态,则会再catch中返回All Promise were rejected

  • 执行最慢的是fulfilled状态,其余的都是rejected状态
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(123);
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(456);
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  reject(789);
});

//all方法中传入的参数,必须是可迭代的(后续文章有奖可迭代对象)
Promise.any([promise1, promise2, promise3])
  .then((res) => {
    console.log(res);//123
  })
  .catch((err) => {
    console.log(err);
  });

  • 所有的都为rejected状态
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(123);
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(456);
  }, 500);
});

const promise3 = new Promise((resolve, reject) => {
  reject(789);
});

//all方法中传入的参数,必须是可迭代的(后续文章有奖可迭代对象)
Promise.any([promise1, promise2, promise3])
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err);///AggregateError: All promises were rejected
  });

你可能感兴趣的:(重学JavaScript高级,javascript,开发语言,ecmascript)