谈到Promise,我们都知道它有一个pending属性,该属性有两种状态:成功(resolved/fulfilled)、失败(rejected),而且一个Promise只可能从“等待”转到“失败”或者“成功”;且状态一旦改变便是不可逆的,谈到Promise,很多人想到的就是解决回调地狱的问题,当我们在需要多个异步请求都执行完再执行下一步操作时,可以考虑使用promise。以下是个人学习Promise记录的知识点
Promise的理解和使用
Promise是什么?
理解
- 抽象表达
 Promise 是一门新的技术(ES6 规范)
 Promise 是 JS 中进行异步编程的新解决方案
 备注:旧方案是单纯使用回调函数
- Promise 的状态改变
 pending 变为 resolved
 pending 变为 rejected
Promise的状态改变
- 具体表达
 说明: 只 2 种, 且一个 Promise 对象只能改变一次,无论变为成功还是失败, 都会有一个结果数据, 成功的结果数据一般称为 Value, 失败的结果数据一般称为 reason
Promise 的基本流程

| const but=document.getElementById("but")but.addEventListener("click",function (){
 let randomNumber=Math.ceil(Math.random()*100)
 
 const p=new Promise(function (resolve, reject){
 setTimeout(()=>{
 if(randomNumber<30){
 
 resolve("中奖了!")
 }else{
 
 reject("抱歉,很遗憾!")
 }
 },1000)
 })
 p.then(value => {
 
 alert(value)
 },reason => {
 
 alert(reason)
 })
 })
 
 | 
为什么要用 Promise?
指定回调函数的方式更加灵活
- 旧的: 必须在启动异步任务前指定
- Promise: 启动异步任务 => 返回Promise对象 => 给Promise对象绑定回调函数(甚至可以任务结束后指定多个回调)
支持链式调用, 可以解决回调地狱问题
- 什么是回调地狱?
- 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
 
- 回调地狱的缺点?
- 解终极解决方案?
如何使用 Promise?
API
不属于new Promise的API(4个)
Promise.prototype.then方法:(onResolved(成功), onRejected(失败)) => {}
- resolve
| let p1 = Promise.resolve(521);
 let p2 = Promise.resolve(
 new Promise((resolve, reject) => {
 
 reject("Error");
 })
 );
 
 p2.then((value) => {
 console.log(value);
 },(reason) => {
 console.log(reason);
 });
 console.log(p1)
 console.log(p2)
 
 | 
**resolve的参数问题**:(以失败的状态为例)
- 如果传入的参数为 非Promise类型的对象, 则返回的结果为成功Promise对象
- 如果传入的参数为 Promise 对象, 则Promise对象的状态决定了 p2执行onResolve还是OnRejected

- reject
| let p1 = Promise.reject(521);
 let p2 = Promise.reject('haha');
 let p3 = Promise.reject(
 new Promise((resolve, reject) => {
 resolve("OK");
 })
 );
 p3.then((value) => {
 console.log(value);
 },(reason) => {
 console.log(reason);
 });
 console.log(p1)
 console.log(p2)
 console.log(p3);
 
 | 
reject的参数问题:
- 如果传入的参数为 非Promise类型的对象, 则new Promise返回的结果永远为失败Promise对象
- 如果传入的参数为 Promise 对象, 则Promise对象的状态决定了 p执行onResolve还是OnRejected

- all
| let p1 = new Promise((resolve, reject) => {
 resolve("OK");
 });
 let p2 = Promise.resolve('Success');
 
 let p3 = Promise.resolve("Oh Yeah");
 const result = Promise.all([p1, p2, p3]);
 console.log(result);
 
 | 
    all方法:(这里以成功为例)
    说明: Promise.all(这里是一个**数组**,数组里面有一个一个的Promise),他返回一个新的 Promise, 只有所有的 Promise都成功才成功, 只要有一个失败了就直接失败。

- race
| 	let p1 = new Promise((resolve, reject) => {
 setTimeout(() => {
 reject("OK");
 }, 1000);
 });
 let p2 = Promise.resolve("Error");
 let p3 = Promise.resolve("Oh Yeah");
 
 const result = Promise.race([p1, p2, p3]);
 console.log(result);
 
 | 
race方法:(这里以成功为例)
说明: 返回一个新的 Promise, 第一个完成的 Promise的结果状态就是最终的结果状

属于new Promise的API
- catch
| let p = new Promise((resolve, reject) => {
 reject('error');
 });
 p.catch(reason => {
 console.log(reason);
 });
 
 | 
catch方法:
说明: 处理错误的方法
Promise 的几个关键问题
如何改变 Promise 的状态?
| 	let p = new Promise((resolve, reject) => {
 
 
 
 reject("error");
 
 
 });
 
 | 

一个 Promise 指定多个成功/失败回调函数, 都会调用吗?
- 当 Promise改变为对应状态时都会调用
- 代码演示
| let p = new Promise((resolve, reject) => {
 resolve("OK");
 });
 
 p.then((value) => {
 console.log(value);
 });
 
 p.then((value) => {
 console.log(value);
 });
 
 | 

改变 Promise 状态和指定回调函数谁先谁后?
- 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
- 如何先改状态再指定回调?
- 在执行器中直接调用 resolve()/reject()
- 延迟更长时间才调用 then()
 
- 什么时候才能得到数据?
- 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
- 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
 
- 代码验证演示
| let startTime=Date.now()
 console.log("开始记时",startTime)
 let p = new Promise((resolve, reject) => {
 setTimeout(() => {
 resolve("OK");
 let endTime=Date.now()-startTime
 console.log("结束记时",endTime)
 }, 1000);
 });
 p.then(
 (value) => {
 console.log(value);
 },
 (reason) => {}
 );
 
 | 

Promise .then()返回的新 Promise 的结果状态由什么决定?
- Promise .then()返回的新 Promise 的结果状态由什么决定?
- 代码验证演示
| let p = new Promise((resolve, reject) => {
 resolve("ok");
 
 });
 
 let result = p.then(
 (value) => {
 
 
 
 
 
 
 return new Promise((resolve, reject) => {
 
 reject("error");
 });
 },
 (reason) => {
 console.warn(reason);
 }
 )
 console.log(result);
 
 result.then((value)=>{
 console.log(value)
 },(reason)=>{
 console.log(reason)
 })
 
 | 
说明: 代码的执行流程
举例:如果开始执行resolve(),那么执行then的onResolved方法
如果onResolved方法返回非Promise对象,那么Promise .then()返回的新Promise的状态就为成功!
如果onResolved方法为Promise对象,那么该Promise返回的状态(成功或者失败/resolve或reject)就决定了Promise .then()返回的新Promise的状态。

Promise 如何串连多个操作任务?
- Promise的 then()返回一个新的 Promise, 可以开成 then()的链式调用
- 通过 then 的链式调用串连多个同步/异步任务
- 代码验证演示
| let p = new Promise((resolve, reject) => {
 setTimeout(() => {
 resolve('OK');
 }, 1000);
 });
 p.then(value => {
 return new Promise((resolve, reject) => {
 resolve("success");
 });
 }).then(value => {
 console.log(value);
 }).then(value => {
 
 console.log(value);
 })
 
 
 | 

Promise 异常传透?
- 当使用 Promise 的 then 链式调用时, 可以在最后指定失败的回调
- 前面任何操作出了异常, 都会传到最后失败的回调中处理
- 代码验证演示
| let p = new Promise((resolve, reject) => {
 setTimeout(() => {
 resolve('OK');
 
 }, 1000);
 });
 p.then(value => {
 
 throw '失败啦!';
 }).then(value => {
 console.log(222);
 }).then(value => {
 console.log(333);
 }).catch(reason => {
 console.warn(reason);
 });
 console.log(p)
 
 | 

如何中断 Promise 链?
- 当使用 Promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
- 办法: 在回调函数中返回一个 pendding 状态的 Promise 对象
- 代码验证演示
| let p = new Promise((resolve, reject) => {
 setTimeout(() => {
 resolve('OK');
 }, 1000);
 });
 let a = p.then(value => {
 console.log(111);
 
 return new Promise(() => {
 });
 }).then(value => {
 console.log(222);
 }).then(value => {
 console.log(333);
 }).catch(reason => {
 console.warn(reason);
 });
 
 
 | 
PromiseE8 之 async 和 await
mdn 文档
async 函数
- 使用async该函数的返回值为 Promise对象
- Promise对象的结果由 async 函数执行的返回值决定
| async function main() {
 
 return 521;
 }
 async function main1() {
 
 return new Promise((resolve, reject) => {
 
 reject("Error");
 });
 }
 async function main2() {
 
 throw "Oh NO";
 }
 let result = main();
 let result1 = main1();
 let result3 = main2();
 console.log(result);
 console.log(result1);
 console.log(result3);
 
 
 | 
await 表达式
- await 右侧的表达式一般为 Promise对象, 但也可以是其它的值
- 如果表达式是 Promise对象, await 返回的是 Promise成功的值
- 如果表达式是其它值, 直接将此值作为 await 的返回值
注意
- await 必须写在 async 函数中, 但 async 函数中可以没有 await
- 如果 await 的 Promise失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
| async function main() {
 let p = new Promise((resolve, reject) => {
 resolve("OK");
 
 });
 
 
 
 
 
 try {
 let res3 = await p;
 console.log(res3)
 } catch (e) {
 
 console.log(e);
 }
 }
 
 | 
总结
Null