JS 异步 Promise、Async、await详解

news/2024/12/26 18:04:01/

目录

一、JS里的同步异步

二、Promise 

1、状态

2、all()、race()、any()

3、简单案例

4、异步执行案例

5、解决异步嵌套繁琐的场景

三、async和await

1、async返回类型

2、async与await结合使用的简单案例

3、解决异步嵌套问题

4、批量请求优化


一、JS里的同步异步

javascript">fun1();
fun2();
fun3();

如以上代码,在同步情况下三个函数应该是依次执行的,fun1执行完执行fun2,最终执行fun3。

什么是异步呢?异步就是大家各做各的,互不干扰,无需互相等待。

但需注意,各做各的,并不意味着乱序。它依然是顺序执行的。只不过,fun1没执行完,fun2已经开始执行了。

JS里的常见异步函数有:settimeout、fetch、setInterval等。

二、Promise 

Promise中文意思是承诺,在JS中,可以通俗理解为:把这个任务(函数)交给我,我来完成。

1、状态

Promise 的三种状态:pending(等待中)、fulfilled(成功)、rejected(失败),且状态改变是不可逆的。

javascript">    const p=new Promise((resolve,reject)=>{resolve("你的成功结果")  //执行更改后Promise状态变成fulfilled//reject("失败的结果")  //执行更改后Promise状态变成rejected//throw 1            //抛出异常和reject的效果一样})p.then(res=>res)//then直接返回会返回包含返回结果的Promise对象,可以通过.then()继续获取.then(res=>{//res对应resolve里的值console.log("fulfilled状态时打印")//以下执行可以返回状态为rejected的Promise给下一级继续执行return new Promise((resolve,reject)=>reject("执行出错"))}).catch(error=>{//error对应reject里的内容console.log("rejected状态时打印")}).finally(()=>{console.log("无论成功还是失败都会打印")})

2、all()、race()、any()

先一句话描述以下Promise.all()、Promise.race()、Promise.any()的区别:

(1) Promise.all() 中的Promise序列会全部执行通过才认为是成功,否则认为是失败;

(2) Promise.race() 中Promise序列中第一个执行完毕的是通过,则认为是成功,如果第一个执行完毕的Promise是rejected,则认为失败;

(3) Promise.any() 中Promise序列只有有一个执行通过,则认为成功,如果全部拒绝,则认为失败。

用一张图来说明all()、any():

any和all类似,区别在于any只要有一个成功就返回成功的结果。

用一张图来说明race():

Both resolve, but promise2 is faster ,从这里可以看出端倪。顾名思义,Promse.race 就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

3、简单案例

通过简单案例了解:

javascript">    //Promise用法const param1 = "normal"; const param2 = "error"; // 第二种情况//1. 创建Promise类的对象const promise01 = new Promise(function customFun(successFun, failFun) {if (param1 === "normal") {successFun("自定义成功的函数执行了!")} else { //失败和成功的逻辑都是自定义的failFun("自定义失败的函数执行了!")}})const promise02 = new Promise(function customFun(successFun, failFun) { // 第二种情况if (param2 === "normal") {successFun("自定义成功的函数执行了!")} else { //失败和成功的逻辑都是自定义的failFun("自定义失败的函数执行了!")}})//2. 执行Promise的返回结果promise01.then(result => {console.log(result)}).catch(error => {console.log(error)})promise02.then(result => {  // 第二种情况console.log(result)}).catch(error => {console.log(error)})

可以看到控制台打印如下:

第一种情况走自定义成功的逻辑,第二种情况走自定义失败的逻辑。

4、异步执行案例

javascript">    //异步常见案例const promise03 = new Promise(() => {console.log("This is Promise constructor.")setTimeout(() => {console.log("Timeout executed!")}, 3000)})promise03.then(result => {console.log(result)})console.log("Test Demo.")

控制台输出:

可以清晰地看到,在Promise被执行时,构造信息就已经打印了,之后,顺序执行了Test Demo, 等待3秒后系统再执行了setTimout里的逻辑。

5、解决异步嵌套繁琐的场景

javascript">    //Promise来规范Timeout嵌套调用的阅读性差问题const promise04 = new Promise((successFun, failFun) => {setTimeout(() => {successFun("timeout 333")}, 3000)})const promise05 = promise04.then((res) => {console.log(res)return new Promise((successFun, failFun) => {setTimeout(() => {successFun("timeout 222")}, 2000)})})promise05.then(res => {console.log(res)})console.log("Test Demo.")

控制台打印:

可以看到,首先打印了Test Demo,3秒后执行了第一各Promise里的内容,执行完第一个Promise里的内容后,再过2秒执行了第二各Promise里的内容。这比setTimout的多层嵌套,可读性更好。

三、async和await

async必须用来修饰函数,用来表示该函数是一个异步函数,await必须和async配套使用。await专门用来修饰Promise的实例化对象。

1、async返回类型

javascript">    //async有返回类型时,以Promise形式返回async function asyncDemo01Fun(){return "Demo01"}async function asyncDemo02Fun(){return Promise.resolve("Demo02")}console.log(asyncDemo01Fun())console.log(asyncDemo02Fun())

打印结果:

可以看到,直接返回结果和利用Promise.resolve返回结果是一样的。

由async修饰的函数,在有返回值时都会直接返回Promise对象,而非直接返回值。

2、async与await结合使用的简单案例

javascript">    //async和await的案例Demoasync function asyncFun1() {const p = new Promise((successFun, failFun) => {setTimeout(() => {successFun({num: 1})}, 3000)})let obj = await p;console.log(obj)}asyncFun1()console.log("Test Demo.")

打印结果:

可以看到,当有await修饰Promise返回对象时,会等待Promise对象执行完成后,再返回结果给对象,最终将获取到的对象值在3秒后打印。

当有await修饰Promise对象时,系统会等待返回值后再返回对象,继续执行。实际上是将异步处理的事件处理完成后再继续执行同步代码。

3、解决异步嵌套问题

javascript">    //async和await的案例Demoasync function asyncFun2() {const p1 = new Promise((successFun, failFun) => {setTimeout(() => {successFun("Demo 333")}, 3000)})let obj1 = await p1;console.log(obj1)const p2 = new Promise((successFun, failFun) => {setTimeout(() => {successFun("Demo 222")}, 2000)})let obj2 = await p2;console.log(obj2)}asyncFun2()console.log("Test Demo.")

控制台打印:

可以看到,首先打印了Test Demo,3秒后执行了第一各Promise里的内容,执行完第一个Promise里的内容后,再过2秒执行了第二各Promise里的内容。这比setTimout的多层嵌套,可读性更好。

4、批量请求优化

以下是同步获取请求结果的案例:

javascript">     const batchReq=async ()=>{const url="https://example.com/api/demo"let rep1=await fetch(`${url}/1/`)let json1=await rep1.json()let name1=await json1.data.namelet rep2=await fetch(`${url}/2/`)let json2=await rep1.json()let name2=await json1.data.namelet rep3=await fetch(`${url}/3/`)let json3=await rep1.json()let name3=await json1.data.nameconsole.log(name1)console.log(name2)console.log(name3)}

以上代码在执行的过程中,由于加了await进行修饰,会依次进行请求,1执行完2执行最后3执行。

如要实现批量请求同时处理,可以参考以下代码:

javascript">    const batchReq = async () => {try {const url = "https://example.com/api/demo"let resp = await Promise.all([fetch(`${url}/1/`), fetch(`${url}/2/`), fetch(`${url}/3/`)])let jsons = resp.map(res => res.json())let values = await Promise.all(jsons)values.map(value => {console.log(value.data.name)})} catch (error) {console.log(error)}}

这样写便可以批量发送请求了。


http://www.ppmy.cn/news/1544351.html

相关文章

实用篇:linux如何查看历史命令(以前使用过的命令)

在 Linux 中,你可以使用以下几种方法查看历史命令: 1. 使用 history 命令 输入 history 命令可以显示你之前执行过的所有命令。默认情况下,它会列出最近的 500 条命令: history2. 使用 ! 符号 你可以使用 ! 符号来执行历史命令…

Android 使用ninja加速编译的方法

ninja的简介 随着Android版本的更迭,makefile体系逐渐增多,导致make单编模块的时间越来越长,每次都需要半个小时甚至更长时间,其原因为每次make都会重新加载所有mk文件,再生成ninja编译,此完整过程十分耗时…

基于YOLO11/v10/v8/v5深度学习的维修工具检测识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

预览 PDF 文档

引言 在现代Web应用中,文件预览功能是非常常见的需求之一。特别是在企业级应用中,用户经常需要查看各种类型的文件,如 PDF、Word、Excel 等。本文将详细介绍如何在Vue项目中实现 PDF 文档的预览功能。 实现原理 后端API 后端需要提供一个…

el-select、el-autocomplete的选项内容过长显示完整内容

问题&#xff1a; el-select、el-autocomplete的选项内容过长需要看清完整内容 解决方案&#xff1a; 使用el-popover悬停显示完整内容 代码&#xff1a; <el-form-item label"备注" prop"remark"><el-autocomplete v-model"form.remar…

php实现sl651水文规约解析

SL651-2014-《水文监测数据通信规约》 1、要素解析说明 39 23 00 00 03 45 0x39查标识符得知为:39H Z 瞬时河道水位、潮位,我们定义为水位 0x23 按照要素标识符的规定,高5bit,低3bit,00100 011 对应的转换为10进制为4与3,也就是水位数据占用4字节,小…

Cocos使用精灵组件显示相机内容

Cocos使用精灵组件显示相机内容 1. 为什么使用精灵渲染 在游戏引擎中&#xff0c;游戏场景内除webview和video外所有的节点都是渲染在Canvas上&#xff0c;这导致了webview和video只能存在于所有节点的最上层或最下层&#xff0c;而这种层级关系会出现节点事件无法正常监听或者…

【1】Excel快速入门的核心概念

1. 工作表 基本工作表 图表工作表 工作表视图 2.表格(Table)&#xff0c;套用表格格式 ​ 名称&#xff08;表&#xff0c;列&#xff09; ​ 结构化引用[列名] ​ 设置表格样式 -可自定义&#xff08;如报表类&#xff09; ​ 数据验证 -交互 &#xff08;输入/输出交…