【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 p1funlet p2value = await p2funconsole.log(p1value)        // p1console.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.mzph.cn/diannao/38167.shtml

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

相关文章

Java SE入门及基础(59) 线程的实现(上) 线程的创建方式 线程内存模型 线程安全

目录 线程&#xff08;上&#xff09; 1. 线程的创建方式 Thread类常用构造方法 Thread类常用成员方法 Thread类常用静态方法 示例 总结 2. 线程内存模型 3.线程安全 案例 代码实现 执行结果 线程&#xff08;上&#xff09; 1. 线程的创建方式 An application t…

利用 Docker 简化 Nacos 部署:快速搭建 Nacos 服务

利用 Docker 简化 Nacos 部署&#xff1a;快速搭建 Nacos 服务 引言 在微服务架构中&#xff0c;服务注册与发现是确保服务间通信顺畅的关键组件。Nacos&#xff08;Dynamic Naming and Configuration Service&#xff09;作为阿里巴巴开源的一个服务发现和配置管理平台&…

任务调度器——任务切换

一、开启任务调度器 函数原型&#xff1a; void vTaskStartScheduler( void ) 作用&#xff1a;用于启动任务调度器&#xff0c;任务调度器启动后&#xff0c; FreeRTOS 便会开始进行任务调度 内部实现机制&#xff08;以动态创建为例&#xff09;&#xff1a; &#xff0…

Linux 安装、配置Tomcat 的HTTPS

Linux 安装 、配置Tomcat的HTTPS 安装Tomcat 这里选择的是 tomcat 10.X ,需要Java 11及更高版本 下载页 ->Binary Distributions ->Core->选择 tar.gz包 下载、上传到内网服务器 /opt 目录tar -xzf 解压将解压的根目录改名为 tomat-10 并移动到 /opt 下, 形成个人…

测评推荐:企业管理u盘的软件有哪些?

U盘作为一种便携的存储设备&#xff0c;方便易用&#xff0c;被广泛应用于企业办公、个人学习及日常工作中。然而&#xff0c;U盘的使用也带来了数据泄露、病毒传播等安全隐患。为了解决这些问题&#xff0c;企业管理U盘的软件应运而生。 本文将对市面上流行的几款U盘管理软件…

Hadoop3:Yarn容量调度器配置多队列案例

一、情景描述 需求1&#xff1a; default队列占总内存的40%&#xff0c;最大资源容量占总资源60%&#xff0c;hive队列占总内存的60%&#xff0c;最大资源容量占总资源80%。 二、多队列优点 &#xff08;1&#xff09;因为担心员工不小心&#xff0c;写递归死循环代码&#…

数据处理:四选一、四关联

今天去面试&#xff0c;面试官们给我一个‘选择’&#xff0c;有四个选项&#xff1a;‘展示你的才华’、‘展示你的美貌’、‘展示你的才华与美貌’、‘都不展示’ {label: “选择”,children: [{label: “展示你的才华”,children: [],isShow: talentModal,click: () > {i…

电路笔记(电源模块): 基于FT2232HL实现的jtag下载器硬件+jtag的通信引脚说明

JTAG接口说明 JTAG 接口根据需求可以选择20针或14针的配置&#xff0c;具体选择取决于应用场景和需要连接的功能。比如之前的可编程逻辑器件XC9572XL使用JTAG引脚&#xff08;TCK、TDI、TDO、TMS、VREF、GND&#xff09;用于与器件进行调试和编程通信。更详细的内容可以阅读11…

51单片机STC8H8K64U通过RA8889/RA8876如何控制彩屏(SPI源码下载)

【硬件部份】 一、硬件连接实物&#xff1a; STC8H系列单片机不需要外部晶振和外部复位&#xff0c;在相同的工作频率下&#xff0c;速度比传统的8051单片机要快12倍&#xff0c;具有高可靠抗干扰的优秀特性&#xff0c;与瑞佑的RA8889/RA8876控制芯片刚好可以完美搭配用于工…

redis实战-缓存雪崩问题及解决方案

定义理解 缓存雪崩是指在同一时间段&#xff0c;大量缓存的key同时失效&#xff0c;或者Redis服务宕机&#xff0c;导致大量请求到达数据库&#xff0c;带来巨大压力 和缓存击穿的区别&#xff1a; 缓存雪崩是由于缓存中的大量数据同时失效或缓存服务器故障引起的&#xff1b…

(漏洞检查项) | 服务端请求伪造 SSRF

(漏洞检查项)|服务端请求伪造 SSRF 漏洞场景 服务端请求伪造&#xff08;SSRF&#xff0c;Server-Side Request Forgery&#xff09;漏洞发生在应用程序允许攻击者通过构造恶意请求&#xff0c;利用服务器端发起HTTP请求&#xff0c;并访问内部资源或进行其他未授权操作。 漏…

css_20_定位

相对定位 设置相对定位 给元素设置 position: relative 即可实现相对定位。 可以使用 left、right、top 、 bottom 四个属性调整位置。 相对定位的参考点是相对自己原来的位置相对定位的特点&#xff1a; 1&#xff0e;不会脱离文档流&#xff0c;元素位置的变化&#xff0c;只…

机器学习周记(第四十五周:Graphformer)2024.6.24~2024.6.30

目录 摘要ABSTRACT1 论文信息1.1 论文标题1.2 论文摘要1.3 论文引言1.4 论文贡献 2 论文模型2.1 问题定义2.2 模型架构2.2.1 自注意下采样模块&#xff08;Self-attention down-sampling module&#xff09;2.2.2 稀疏图自注意力机制&#xff08;Sparse graph self-attention m…

python自动移除excel文件密码(小工具)

安装 msoffcrypto-tool 使用pip命令安装: 打开命令行工具&#xff08;如终端、命令提示符或Powershell&#xff09;&#xff0c;然后输入以下命令来安装msoffcrypto-tool&#xff1a; pip install msoffcrypto-tool库&#xff0c;进行自动移除excel文件密码 import msoffcrypt…

【C++】using namespace std 到底什么意思

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文作为 JohnKi 的学习笔记&#xff0c;引用了部分大佬的案例 &#x1f4e2;未来很长&a…

新手练习项目 7:猜数字游戏

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#xff09; 目录 一、项目描述二、项目实现三、项目步骤四、项目扩展方向 更多项目内容&#xff0c;请关注我、订…

comsol学习笔记

comsol岩土力学与流固耦合的学习 comsol的相关视频教程 https://www.bilibili.com/video/BV1Cu4y1r7Gn/?spm_id_from333.337.search-card.all.click&vd_source02b2bad477a153eaeb9c48cbbedaf8df [这里面有讲解地应力平衡技术] https://www.bilibili.com/video/BV17C4y1j…

打靶记录——靶机medium_socnet

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

【Spring Boot】认识 JPA 的接口

认识 JPA 的接口 1.JPA 接口 JpaRepository2.分页排序接口 PagingAndSortingRepository3.数据操作接口 CrudRepository4.分页接口 Pageable 和 Page5.排序类 Sort JPA 提供了操作数据库的接口。在开发过程中继承和使用这些接口&#xff0c;可简化现有的持久化开发工作。可以使 …

springboot学习,如何用redission实现分布式锁

目录 一、springboot框架介绍二、redission是什么三、什么是分布式锁四、如何用redission实现分布式锁 一、springboot框架介绍 Spring Boot是一个开源的Java框架&#xff0c;由Pivotal团队&#xff08;现为VMware的一部分&#xff09;于2013年推出。它旨在简化Spring应用程序…