zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Promise入门

2023-03-14 22:55:52 时间

文章目录


✨文章有误请指正,如果觉得对你有用,请点赞收藏关注一波,谢谢支持😘

前言

一、Promise的理解和使用

1.Promise是什么?

1.1.1 理解

1.1.2 Promise的状态改变

1.1.3 Promise 的基本流程

1.1.4 Promise 的基本使用

2.为什么要用 Promise?

1.2.1 指定回调函数的方式更加灵活

1.2.2 支持链式调用, 可以解决回调地狱问题

3.如何使用 Promise?

1.3.1 API

1.3.1.1 不属于new Promise的API(4个)

1.3.1.2 属于new Promise的API

1.3.2 Promise 的几个关键问题

1.3.2.1 如何改变 Promise 的状态?

1.3.2.2 一个 Promise 指定多个成功/失败回调函数, 都会调用吗?

1.3.2.3 改变 Promise 状态和指定回调函数谁先谁后?

1.3.2.4 Promise .then()返回的新 Promise 的结果状态由什么决定?

1.3.2.5 Promise 如何串连多个操作任务?

1.3.2.6 Promise 异常传透?

1.3.2.7 如何中断 Promise 链?

1.3.3 PromiseE8 之 async 和 await

1.3.1 mdn 文档

1.3.2 async 函数

1.3.3 await 表达式

1.3.4 注意

总结

✨文章有误请指正,如果觉得对你有用,请点赞收藏关注一波,谢谢支持😘

前言


谈到Promise,我们都知道它有一个pending属性,该属性有两种状态:成功(resolved/fulfilled)、失败(rejected),而且一个Promise只可能从“等待”转到“失败”或者“成功”;且状态一旦改变便是不可逆的,谈到Promise,很多人想到的就是解决回调地狱的问题,当我们在需要多个异步请求都执行完再执行下一步操作时,可以考虑使用promise。以下是个人学习Promise记录的知识点

一、Promise的理解和使用

1.Promise是什么?

1.1.1 理解


  • 抽象表达
    Promise 是一门新的技术(ES6 规范)
    Promise 是 JS 中进行异步编程的新解决方案
    备注:旧方案是单纯使用回调函数
  • Promise 的状态改变
    pending 变为 resolved
    pending 变为 rejected

1.1.2 Promise的状态改变


  • 具体表达
    说明: 只 2 种, 且一个 Promise 对象只能改变一次,无论变为成功还是失败, 都会有一个结果数据, 成功的结果数据一般称为 Value, 失败的结果数据一般称为 reason

1.1.3 Promise 的基本流程

image.png

1.1.4 Promise 的基本使用

  • 代演示
const but=document.getElementById("but")
but.addEventListener("click",function (){
    let randomNumber=Math.ceil(Math.random()*100)
    //这里new Promise
       const p=new Promise(function (resolve, reject){
           setTimeout(()=>{
               if(randomNumber<30){
               //成功的状态
               resolve("中奖了!")
           }else{
               //失败的的状态
               reject("抱歉,很遗憾!")
           }
           },1000)
       })
        p.then(value => {
        //这里是p的pending属性为resolve/fulfilled
            alert(value)
        },reason => {
        //这里是p的pending属性为rejected
            alert(reason)
        })
})

2.为什么要用 Promise?

1.2.1 指定回调函数的方式更加灵活


  • 旧的: 必须在启动异步任务前指定
  • Promise: 启动异步任务 => 返回Promise对象 => 给Promise对象绑定回调函数(甚至可以任务结束后指定多个回调)

1.2.2 支持链式调用, 可以解决回调地狱问题


  • 什么是回调地狱?
    • 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
  • 回调地狱的缺点?
    • 不便于阅读
    • 不便于异常处理
  • 解终极解决方案?
    • Promise链式调用

3.如何使用 Promise?

1.3.1 API

1.3.1.1 不属于new Promise的API(4个)


Promise.prototype.then方法:(onResolved(成功), onRejected(失败)) => {}

  1. resolve

let p1 = Promise.resolve(521);
let p2 = Promise.resolve(
new Promise((resolve, reject) => {
  // resolve('OK');
  reject("Error");
})
);
// 如果不对出错进行处理(指定错误回调),控制台就会报错
p2.then((value) => {
console.log(value);
},(reason) => {
console.log(reason);
});
console.log(p1)
console.log(p2)
resolve的参数问题:(以失败的状态为例)

1.如果传入的参数为 非Promise类型的对象, 则返回的结果为成功Promise对象

2.如果传入的参数为 Promise 对象, 则Promise对象的状态决定了 p2执行onResolve还是OnRejected

image.png

2.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的参数问题:

1.如果传入的参数为 非Promise类型的对象, 则new Promise返回的结果永远为失败Promise对象

2.如果传入的参数为 Promise 对象, 则Promise对象的状态决定了 p执行onResolve还是OnRejected

image.png

3.all


let p1 = new Promise((resolve, reject) => {
 resolve("OK");
});
let p2 = Promise.resolve('Success');
// let p2 = Promise.reject("Error");
let p3 = Promise.resolve("Oh Yeah");
const result = Promise.all([p1, p2, p3]);
console.log(result);

all方法:(这里以成功为例)

说明: Promise.all(这里是一个数组,数组里面有一个一个的Promise),他返回一个新的 Promise, 只有所有的 Promise都成功才成功, 只要有一个失败了就直接失败。

image.png

4.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的结果状态就是最终的结果状

image.png

1.3.1.2 属于new Promise的API

1.catch


let p = new Promise((resolve, reject) => {
    reject('error');
});
p.catch(reason => {
    console.log(reason);
});

catch方法:

说明: 处理错误的方法

1.3.2 Promise 的几个关键问题

1.3.2.1 如何改变 Promise 的状态?


  • 改变 Promise 的状态的几种方法:代码演示
    
let p = new Promise((resolve, reject) => {
 //1. resolve 函数
 // resolve("ok"); // pending   => fulfilled (resolved)
 //2. reject 函数
 reject("error"); // pending  =>  rejected
 //3. 抛出错误
 // throw "出问题了";
});

image.png

1.3.2.2 一个 Promise 指定多个成功/失败回调函数, 都会调用吗?


  • 当 Promise改变为对应状态时都会调用
  • 代码演示

let p = new Promise((resolve, reject) => {
 resolve("OK"); //如果注释掉resolve(),那么p的状态就还是pending,即状态未发生改变,不会调用then
});
///指定回调 - 1
p.then((value) => {
 console.log(value);
});
//指定回调 - 2
p.then((value) => {
 console.log(value);
});

image.png

1.3.2.3 改变 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) => {}
);

image.png

1.3.2.4 Promise .then()返回的新 Promise 的结果状态由什么决定?


  • Promise .then()返回的新 Promise 的结果状态由什么决定?
  • 代码验证演示

let p = new Promise((resolve, reject) => {
 resolve("ok");
 // reject("no");
});
//执行 then 方法
let result = p.then(
 (value) => {
     // console.log(value);
   //1. 抛出错误 rejected
   //   throw "出了问题";
   //2. 返回结果是非 Promise 类型的对象 fulfilled
   //   return 521;
   //3. 返回结果是 Promise 对象 fulfilled/rejected
   return new Promise((resolve, reject) => {
     // resolve("success");
     reject("error");
   });
 },
 (reason) => {
   console.warn(reason);
 }
)
console.log(result);
// 这里result返回的依旧是一个Promise,以下是对Promise的成功或失败的处理
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的状态。

image.png

1.3.2.5 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 => {
//因为上个then没有返回任何东西所以输出undefined
   console.log(value);
})

image.png

1.3.2.6 Promise 异常传透?


  • 当使用 Promise 的 then 链式调用时, 可以在最后指定失败的回调
  • 前面任何操作出了异常, 都会传到最后失败的回调中处理
  • 代码验证演示

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('OK');
        // reject('Err');
    }, 1000);
});
p.then(value => {
    // console.log(111);
    throw '失败啦!';
}).then(value => {
    console.log(222);
}).then(value => {
    console.log(333);
}).catch(reason => { //用then也可以捕获异常,不过then要传两个参数
    console.warn(reason);
});
console.log(p)

image.png

1.3.2.7 如何中断 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);
});

1.3.3 PromiseE8 之 async 和 await

1.3.1 mdn 文档

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function


https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await

1.3.2 async 函数


  • 使用async该函数的返回值为 Promise对象
  • Promise对象的结果由 async 函数执行的返回值决定

async function main() {
 //1. 如果返回值是一个非Promise类型的数据 则状态为成功,返回一个成功的promise对象
 return 521;
}
async function main1() {
 //2. 如果返回的是一个Promise对象 则状态取决于返回结果
 return new Promise((resolve, reject) => {
   // resolve('OK'); //成功
   reject("Error"); //失败
 });
}
async function main2() {
 // 3. 抛出异常 返回一个失败的promise对象
 throw "Oh NO";
}
let result = main();
let result1 = main1();
let result3 = main2();
console.log(result);
console.log(result1);
console.log(result3);

1.3.3 await 表达式

  • await 右侧的表达式一般为 Promise对象, 但也可以是其它的值
  • 如果表达式是 Promise对象, await 返回的是 Promise成功的值
  • 如果表达式是其它值, 直接将此值作为 await 的返回值

1.3.4 注意


  • await 必须写在 async 函数中, 但 async 函数中可以没有 await
  • 如果 await 的 Promise失败了, 就会抛出异常, 需要通过 try…catch 捕获处理



async function main() {
  let p = new Promise((resolve, reject) => {
    resolve("OK");
    // reject("Error");
  });
  //1. 右侧为promise的情况
  // let res = await p;
  //2. 右侧为其他类型的数据
  // let res2 = await 20;
  //3. 如果promise是失败的状态
  try {
    let res3 = await p;
    console.log(res3)
  } catch (e) {
    //catch捕获失败状态
    console.log(e);
  }
}

总结


觉得有帮助的,记得给个赞👍

以上就是个人学习Promise的相关知识点,如有错漏之处,敬请指正。