【JS异步编程】async/await——用同步代码写异步

历史小剧场

懂得暴力的人,是强壮的;懂得克制暴力的人,才是强大的。----《明朝那些事儿》

什么是 async/await

  • async: 声明一个异步函数
    • 自动将常规函数转换成Promise,返回值也是一个Promise对象;
    • 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数;
    • 异步函数内部可以使用await
  • await: 暂停异步的功能执行
    • 放置在Promise调用之前,await强制其他代码等待,直到Promise完成并返回结果;
    • 只能与Promise一起使用,不适用回调;
    • 只能在async函数内部使用

简单使用

async function fun() {
    // let name = await "后盾人"
     // console.log(name) 
     let name = await new Promise(resolve => {
         setTimeout(() => {
             resolve("后盾人")
         }, 1000)
     })
     let site = await new Promise(resolve => {
         setTimeout(() => {
             resolve("www.houdunren.com")
         }, 2000)
     })
     console.log("name => ", name)
     console.log("site => ", site)
 }

 // console.log(fun()) // Promise {<fulfilled>: undefined}
 // fun().then(value => console.log(value))
 fun()

声明方式

  1. 普通函数
async function get(dictType) {
   const dict = await ajax(`http://xxx?dict=${dictType}`)
   console.log("dict => ", dict)
}
  1. 函数表达式
const foo = async function (dictType) {
   const dict = await ajax(`http://xxx?dict=${dictType}`)
   console.log("dict => ", dict)
}
  1. 箭头函数
const foo = async () => {
	const dict = await ajax(`http://xxx?dict=${dictType}`)
   	console.log("dict => ", dict)
}
  1. 对象
let obj = {
	async get() {
		const dict = await ajax(`http://xxx?dict=${dictType}`)
   		console.log("dict => ", dict)
	}
}
  1. class 类
class Dict {
    constructor(dictType) {
        this.dictType = dictType
    }
    async get() {
        let dictList = await ajax(`http://xxx?dict=${this.dictType}`)
        dictList.data.forEach(dictItem => {
            dictItem.AREA_NAME += '-心潮'
        })
        return dictList.data;
    }
}
new Dict('DICT_DRUG_AREA').get().then(value => {
    console.log("value => ", value)
})

错误处理

  1. async错误处理
async function get() {
    console.log(a)
}
get().catch(error => {
    console.log("error => ", error) // error =>  ReferenceError: a is not defined
})


async function get2() {
    throw new Error("用户不存在")
}
get2().catch(error => {
    console.log("error2 => ", error) // error2 =>  Error: 用户不存在
})
  1. await 错误处理
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="../js/ajax.js"></script>
    <script>
        // 1、在函数外部处理
        // async function get(dictType) {
        //     let dictList = await ajax(`ahttp://xxx?dict=${dictType}`)
        //     return dictList;
        // }
        // get('DICT_DRUG_AREA').then(res => {
        //     console.log("res => ", res.data)
        // }).catch(error => {
        //     console.log("error => ", error.message)
        // })


        // 2、在函数内部处理
        async function get(dictType) {
            try {
                let dictList = await ajax(`ahttp://xxx?dict=${dictType}`)
                return dictList;
            } catch (error) {
                alert(error.message)
            }
        }
        get('DICT_DRUG_AREA').then(res => {
            console.log("res => ", res.data)
        })
    </script>
</body>
</html>

ajax.js文件

class ParamError extends Error {
    constructor(msg) {
        super(msg)
        this.name = 'ParamError'
    }
}

class HttpError extends Error {
    constructor(msg) {
        super(msg)
        this.name = 'HttpError'
    }
}

function ajax(url) {
    // 自定义错误处理
    if (!/^http/.test(url)) {
        throw new ParamError("请求地址格式错误")
    }
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.open("POST", url)
        xhr.send()
        xhr.onload = function () {
            if (this.status === 200) {
                resolve(JSON.parse(this.response))
            } else if (this.status === 404) {
                // 自定义错误处理
                reject(new HttpError("响应内容不存在"))
            } else {
                reject("加载失败")
            }
        }
        xhr.onerror = function () {
            reject(this)
        }
    })
}

场景案例

1. async延时函数
const sleep = async (delay = 2000) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve()
        }, delay)
    })
}


const show = async () => {
    for (name of ['小芳', '小红']) {
        await sleep()
        console.log(name)
    }
}
show()
2. await 进度条
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #loading {
            width: 0vw;
            background-color: blueviolet;
            height: 10vh;
            display: flex;
            color: white;
            align-items: center;
            justify-content: center;
            transition: all 1s ease-out;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <div id="loading">0%</div>
    <script src="../js/ajax.js"></script>
    <script>
        (async (dicts) => {
            const loading = document.querySelector("#loading");
            for (let i = 0, len = dicts.length; i < len; i++) {
                await ajax(`http://xxx?dict=${dicts[i]}`)
                loading.style.width = `${(i + 1) / len * 100}vw`
                loading.textContent = `${Math.round((i + 1) / len * 100)}%`
            }
        })(Array(50).fill('DICT_DRUG_AREA'))
    </script>
</body>
</html>
3. await 并行技巧

首先,这里,有两个异步任务

function p1() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve("p1")
        }, 2000)
    })
}

function p2() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve("p2")
        }, 2000)
    })
}

当我们正常使用时,会顺序隔两秒打印p1和p2,代码如下:

// 按顺序打印
async function fun() {
    let p1value = await p1()
    console.log(p1value)
    let p2value = await p2()
    console.log(p2value)
}
fun()

显然,这不是我们想要的效果。接着,我们这样修改

fun()

// 过两秒之后 并行打印
async function fun() {
    let p1value = p1()
    let p2value = p2()
    setTimeout(() => {
        console.log(p1value)        // Promise { 'p1' }
        console.log(p2value)        // Promise { 'p2' }
    }, 2000)
}

这里,我们没有使用await,那么返回的是Promise对象。
如上代码,运行之后,会隔两秒钟之后同时打印 Promise { ‘p1’ } 和 Promise { ‘p2’ }

这样,我们就找到了并行打印技巧

方案一

async function fun() {
    let p1fun = p1()
    let p2fun = p2()

    let p1value = await p1fun
    let p2value = await p2fun
    console.log(p1value)        // p1
    console.log(p2value)        // p2
}

方案二 (推荐)

async function fun2() {
    const res = await Promise.all([p1(), p2()])
    console.log("res => ", res)     // res =>  [ 'p1', 'p2' ]
}
fun2()

小结

Async/Await让我们用少量的代码来使用Promise,我们可以将一些有依赖关系的回调函数的处理逻辑放在async里面,然后在非async的区域使用,这样可以减少then或者catch回调。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/759088.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gin 服务端无法使用sse流式nginx配置

我在本地使用 gin 可以流式的将大模型数据传递给前端。但是当我部署到服务器中时&#xff0c;会阻塞一段时间&#xff0c;然后显示一大段文本。 起初我怀疑是gin 没有及时将数据刷到管道中&#xff0c;但是经过测试&#xff0c;还是会阻塞。 c.Writer.(http.Flusher).Flush()最…

HTML5的多线程技术:Web Worker API

Web Workers API 是HTML5的一项技术&#xff0c;它允许在浏览器后台独立于主线程运行脚本&#xff0c;即允许进行多线程处理。这对于执行密集型计算任务特别有用&#xff0c;因为它可以防止这些任务阻塞用户界面&#xff0c;从而保持网页的响应性和交互性。Web Workers在自己的…

CAS服务端部署

部署CAS Cas服务端其实就是一个war包。 在资源\cas\source\cas-server-4.0.0-release\cas-server-4.0.0\modules目录下cas-server-webapp-4.0.0.war 将其改名为cas.war放入tomcat目录下的webapps下。启动tomcat自动解压war包。浏览器输入 登录页面 http://localhost:8080/ca…

43 - 部门工资前三高的所有员工(高频 SQL 50 题基础版)

43 - 部门工资前三高的所有员工 # dense_rank 排名selectDepartment,Employee,Salary from(selectd.name as Department,e.name as Employee,e.salary as Salary,(dense_rank() over (partition by d.name order by e.salary desc)) as rankingfrom Employee e left join Depar…

【设计模式】行为型-状态模式

在变幻的时光中&#xff0c;状态如诗篇般细腻流转。 文章目录 一、可调节的灯光二、状态模式三、状态模式的核心组件四、运用状态模式五、状态模式的应用场景六、小结推荐阅读 一、可调节的灯光 场景假设&#xff1a;我们有一个电灯&#xff0c;它可以被打开和关闭。用户可以…

Nvidia jetson Orin/Nano + 智能座舱摄像头实现车载AI视觉

智能座舱系统包括DMS&#xff08;Driver Monitor System&#xff09;驾驶员疲劳监测系统和OMS乘员监测系统&#xff0c;通过在车内安装摄像头感知驾驶员和乘客的行为以及车内状况&#xff1a;DMS摄像头能够实现驾驶员疲劳监测、驾驶员注意力监测、危险驾驶行为监测以及驾驶员身…

【python】python基于tkinter的学生成绩管理系统(源码+数据文件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

如何做到高级Kotlin强化实战?(一)

高级Kotlin强化实战&#xff08;一&#xff09; 第一章 Kotlin 入门教程1.Kotlin 入门介绍2.Kotlin 与 Java 比较 第一章 Kotlin 入门教程 1.Kotlin 入门介绍 Kotlin 概述 Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言。它主要是 JetBrains 开发团队所开发出来的编程…

打靶记录——靶机medium_socnet

靶机下载地址 https://www.vulnhub.com/entry/boredhackerblog-social-network,454/ 打靶过程 由于靶机和我的Kali都处于同一个网段&#xff0c;所以使用arpscan二次发现技术来识别目标主机的IP地址 arpscan -l除了192.168.174.133&#xff0c;其他IP都是我VMware虚拟机正…

算法力扣刷题 二十六【459.重复的子字符串】

前言 字符串篇&#xff0c;继续。 记录 二十六【459.重复的子字符串】 一、题目阅读 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例…

在TkinterGUI界面显示WIFI网络(ESP32s3)摄像头画面

本实验结合了之前写过的两篇文章Python调用摄像头&#xff0c;实时显示视频在Tkinter界面以及ESP32 S3搭载OV2640摄像头释放热点&#xff08;AP&#xff09;工作模式–Arduino程序&#xff0c;当然如果手头有其他可以获得网络摄像头的URL即用于访问摄像头视频流的网络地址&…

浅谈Tomcat

文章目录 一、什么是Tomcat&#xff1f;二、Tomcat的下载安装三、使用tomcat访问资源 一、什么是Tomcat&#xff1f; Tomcat 就是一个 HTTP 服务器。 前面我们聊了HTTP服务器&#xff0c;像我们在网页输入URL&#xff0c;其实就是在给人家的HTTP服务器发送请求&#xff0c;既…

计算机网络之数据通信原理(中)

上节内容传送口&#xff1a;数据通信原理基础 1.数据传输方式 1.1并行传输 并行传输: 字符编码的各个比特同时传输 特点&#xff1a; 一个比特时间内可传输一个字符&#xff0c;传输速度快&#xff0c;每个比特传输要求一个单独的信道支持&#xff0c;通信成本高&#xf…

红黑树插入删除流程(流程图)

红黑树插入删除流程&#xff08;流程图&#xff09; 红黑树性质 左根右(二叉树&#xff09;根叶黑&#xff08;根节点是黑色的&#xff09;不红红&#xff08;不存在相邻两个红色节点&#xff09;黑路同&#xff08;对于每个节点&#xff0c;从该节点出发到任一空叶节点所经过…

收银系统源码-千呼新零售【全场景收银】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

intellij idea中使用R语言plot画图无图像问题

1、在intellij idea中使用R语言plot函数时&#xff0c;会遇到各种各样的问题&#xff0c;会出现图片不显示问题&#xff0c; 可以看到&#xff0c;目前我电脑r语言版本为4.2.1&#xff0c;输入下面代码&#xff1a; # # 安装包 # install.packages(ggplot2) # library(ggplot2…

理解MySQL核心技术:外键的概念作用和应用实例

引言 在数据库管理系统&#xff08;DBMS&#xff09;中&#xff0c;外键&#xff08;Foreign Key&#xff09;是维持数据一致性和实现数据完整性的重要工具。本文将详细介绍MySQL外键的基本概念、作用&#xff0c;以及相关的操作指南和应用实例&#xff0c;帮助读者掌握并灵活…

实现了Map接口的HashMap

HashMap 底层主要由以下几个部分组成&#xff1a; 数组 (Node<K,V>[] table): 这是一个数组&#xff0c;存储的是链表的头节点。默认大小为 16。链表 (Linked List): 当发生哈希冲突时&#xff0c;即不同的键具有相同的哈希值&#xff0c;HashMap 使用链表来解决冲突。链…

2024年06月CCF-GESP编程能力等级认证Scratch图形化编程一级真题解析

本文收录于《Scratch等级认证CCF-GESP图形化真题解析》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 一、单选题(每题 3 分,共 30 分) 第1题 小杨父母带他到某培训机构给他报名参加 CCF 组织的 GESP 认证考试的第 1级,那他可以选择的认证语言有几种?( ) A、…

C++ | Leetcode C++题解之第204题计数质数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countPrimes(int n) {vector<int> primes;vector<int> isPrime(n, 1);for (int i 2; i < n; i) {if (isPrime[i]) {primes.push_back(i);}for (int j 0; j < primes.size() && i …