JS 异步 Promise、Async、await详解

news2024/12/24 22:18:41

目录

一、JS里的同步异步

二、Promise 

1、状态

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

3、简单案例

4、异步执行案例

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

三、async和await

1、async返回类型

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

3、解决异步嵌套问题

4、批量请求优化


一、JS里的同步异步

fun1();
fun2();
fun3();

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

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

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

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

二、Promise 

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

1、状态

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

    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、简单案例

通过简单案例了解:

    //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、异步执行案例

    //异步常见案例
    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、解决异步嵌套繁琐的场景

    //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返回类型

    //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结合使用的简单案例

    //async和await的案例Demo
    async 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、解决异步嵌套问题

    //async和await的案例Demo
    async 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、批量请求优化

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

     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.name

        let rep2=await fetch(`${url}/2/`)
        let json2=await rep1.json()
        let name2=await json1.data.name

        let rep3=await fetch(`${url}/3/`)
        let json3=await rep1.json()
        let name3=await json1.data.name

        console.log(name1)
        console.log(name2)
        console.log(name3)
    }

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

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

    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.coloradmin.cn/o/2231454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vue3】Vue3相比Vue2有哪些新特性?全面解析与应用指南

🧑‍💼 一名茫茫大海中沉浮的小小程序员🍬 👉 你的一键四连 (关注 点赞收藏评论)是我更新的最大动力❤️! 📑 目录 🔽 前言1️⃣ 响应式系统的改进2️⃣ Composition API的引入3️⃣ 更好的Type…

Vue 事件阻止 e.preventDefault();click.prevent

Vue 事件阻止 Vue 事件阻止 e.preventDefault(); click.prevent修饰符

基于vue3和elementPlus的el-tree组件,实现树结构穿梭框,支持数据回显和懒加载

一、功能 功能描述 数据双向穿梭:支持从左侧向右侧转移数据,以及从右侧向左侧转移数据。懒加载支持:支持懒加载数据,适用于大数据量的情况。多种展示形式:右侧列表支持以树形结构或列表形式展示。全选与反选&#xf…

leetcode-21-合并两个有序链表

题解: 1、初始化哑节点dum 2、 3、 代码: 参考:leetcode-88-合并两个有序数组

WPF怎么通过RestSharp向后端发请求

1.下载RestSharpNuGet包 2.请求类和响应类 public class ApiRequest {/// <summary>/// 请求地址/// </summary>public string Route { get; set; }/// <summary>/// 请求方式/// </summary>public Method Method { get; set; }/// <summary>//…

指派问题的求解

实验类型&#xff1a;◆验证性实验 ◇综合性实验 ◇设计性实验 实验目的&#xff1a;学会使用Matlab求解指派问题。 实验内容&#xff1a;利用Matlab编程实现枚举法求解指派问题。 实验例题&#xff1a;有5人分别对应完成5项工作&#xff0c;其各自的耗费如下表所示&#…

vue3 gsap 基于侦听器的动画

1、gsap实现动画 https://gsap.com/ .以上来自baidu ai 2、代码&#xff1a; 安装gsap&#xff1a;pnpm install gsap <script setup> import { ref, reactive, watch } from vue import gsap from gsapconst number ref(0) const tweened reactive({number: 0 })wat…

Flutter CustomScrollView 效果-顶栏透明与标签栏吸顶

CustomScrollView 效果 1. 关键组件 CustomScrollView, SliverOverlapAbsorber, SliverPersistentHeader 2. 关键内容 TLDR SliverOverlapAbsorber 包住 pinned为 true 的组件 可以被CustomScrollView 忽略高度。 以下的全部内容的都为了阐述上面这句话。初阶 Flutter 开发知…

江协科技STM32学习- P29 实验- 串口收发HEX数据包/文本数据包

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

4.1 进程管理

在异步通信中&#xff0c;每个字符包含1位起始位、7位数据位和2位终止位&#xff0c;若每秒钟传送500个字符&#xff0c;则有效数据速率为&#xff08; &#xff09;。 A. 500b/s B. 700b/s C. 3500b/s D. 5000b/s 正确答案是 C。 解析 本题考查异步传输协议基础知识。 根据题目…

[进阶]集合的进阶(1)泛型

文章目录 泛型的深入泛型的细节泛型可以在很多地方定义泛型的继承和通配符总结 泛型的深入 泛型:是JDK5中引入的特性&#xff0c;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查 泛型的格式:<数据类型> 注意:泛型只能引用数据类型 泛型的好处 统一了数据类型…

GB/T 28046.3-2011 道路车辆 电气及电子设备的环境条件和试验 第3部分:机械负荷(4)

写在前面 本系列文章主要讲解道路车辆电气及电子设备的环境条件和试验GB/T 28046标准的相关知识&#xff0c;希望能帮助更多的同学认识和了解GB/T 28046标准。 若有相关问题&#xff0c;欢迎评论沟通&#xff0c;共同进步。(*^▽^*) 第3部分&#xff1a;机械负荷 4.1 振动 …

【案例】旗帜飘动

开发平台&#xff1a;Unity 6.0 开发工具&#xff1a;Shader Graph 参考视频&#xff1a;Unity Shader Graph 旗帜飘动特效   一、效果图 二、Shader Graph 路线图 三、案例分析 核心思路&#xff1a;顶点偏移计算 与 顶点偏移忽略 3.1 纹理偏移 视觉上让旗帜保持动态飘动&a…

小白从零开始配置pytorch环境

一、下载ANACONDA 官方网址Anaconda Installers and Packages 笔者选择的是Anaconda3-5.3.0-Windows-x86_64.exe版本。全程安装可以手机开热点&#xff0c;会快一点。 二、查看电脑是否有显卡 1、打开任务管理器 2、查看电脑CUBA版本&#xff0c;如上篇文章所提到查看CUDA-V…

11.1 网络编程-套接字

练习&#xff1a; 使用搭建好的服务器和客户端&#xff0c;实现一个完整的注册&#xff0c;登录功能 服务器使用链表 文件IO的形式去记录账号和密码 代码实现&#xff1a; 服务器端&#xff1a; #include <myhead.h> struct Pack{char flags;char na…

基于MATLAB的战术手势识别

手势识别的研究起步于20世纪末&#xff0c;由于计算机技术的发展&#xff0c;特别是近年来虚拟现实技术的发展&#xff0c;手势识别的研究也到达一个新的高度。熵分析法是韩国的李金石、李振恩等人通过从背景复杂的视频数据中分割出人的手势形状&#xff0c;然后计算手型的质心…

面试题整理 1

实际参与的某公司面试&#xff0c;总结了遇到的值得整理记录的面试题。 目录 相对路径 正序判断 倒序判断 输出部门负责人及下级 代码实现 最终效果 科目平均分 SQL筛选 代码实现 分组错误 原因 查看版本 确认模式 设置模式 相遇洞穴 代码实现 方式一&#xf…

mysql查表相关练习

作业要求&#xff1a; 单表练习&#xff1a; 1 . 查询出部门编号为 D2019060011 的所有员工 2 . 所有财务总监的姓名、编号和部门编号。 3 . 找出奖金高于工资的员工。 4 . 找出奖金高于工资 40% 的员工。 5 找出部门编号为 D2019090011 中所有财务总监&#xff0c;和…

基于yolov5的输电线,电缆检测系统,支持图像检测,视频检测和实时摄像检测功能(pytorch框架,python源码)

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; yolov5&#xff0c;输电线(线缆)检测系统&#xff0c;系统既支持图像检测&#xff0c;也支持视频和摄像实时检测【pytorch框架】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的输…

C语言另一种编码方式开发状态机(无switch)

目录 概述 一、开发环境 二、coding 三、运行结果 四、总结 概述 状态机编码思想&#xff0c;在很多领域都随处可见&#xff0c;传统的coding方式使用switch case来实现&#xff0c;状态跳转可读性差&#xff0c;咋们换一种思路来实现状态机开发&#xff0c;该方式 拓展好…