javaScript浅谈----asyncawait

news2025/1/12 22:06:05

什么是 async ?

async/await 是 ES7 的标准,Promise 是 ES6 标准,async/await 这套 API 也是用来帮助我们写异步代码的,它是构建在 Promise 之上的。

async的特点:

  • async 一般不单独使用,而是和 await 一起使用。
  • async 函数被调用的时候,会立即返回一个 Promise
  • async 函数执行到 await 的时候,会暂停整个 async 函数的执行进程并出让其控制权,只有当其等待的基于 Promise 的异步操作被兑现或被拒绝之后才会恢复进程。

await的特点:

  • await 不能单独使用,如果在非 async 函数内部被调用会报错。
  • await 后面一般跟一个 Promise ,也可以是其他的,比如一个数值,或者一个变量,或者一个函数。如果 await 后面不是一个 Promise 就会返回一个已经 resolvePromise
  • await 相当于 Promisethen

为什么要使用 async ?

(一) 隐藏 Promise ,更易于理解

假设我们想请求一个接口,然后把响应的数据打印出来,并且捕获异常。用 Promise 大概是这样写:

 function logFetch(url) {return fetch(url).then((response) => response.text()).then((text) => {console.log(text);}).catch((err) => {console.error("fetch failed", err);});} 

如果用 async 函数来写,大概是这个样子:

 async function logFetch(url) {try {const response = await fetch(url);console.log(await response.text());} catch (err) {console.log("fetch failed", err);}} 

虽然代码的行数差不多,但是代码看起来更加简洁,少了很多 then 的嵌套。请求一个接口数据,然后打印,就像你看到的,很简单,可阅读性更高。

(二)用同步的思路写异步逻辑

async/await 最大的优势就是我们可以用同步的思路来写异步的业务逻辑,所以代码整体看起来更加容易看懂。

下面举个例子

我们想获取一个网络资源的大小,如果使用 Promise 大概可能是这个样子:

 function getResponseSize(url) {return fetch(url).then((response) => {const reader = response.body.getReader();let total = 0;return reader.read().then(function processResult(result) {if (result.done) return total;const value = result.value;total += value.length;console.log("Received chunk", value);return reader.read().then(processResult);});}); 

这样就形成了最初“回调地狱",这个代码也并不是很好理解,因为中间有一个循环的过程,而且这个执行的过程的异步的,并不像我们之前学到的一个链式调用能解决的。

接下来我们看一下 async 函数是怎么处理的。

 async function getResponseSize(url) {const response = await fetch(url);const reader = response.body.getReader();let result = await reader.read();let total = 0;while (!result.done) {const value = result.value;total += value.length;console.log("Received chunk", value);result = await reader.read();}return total;} 

这样看起来就更加流畅了,因为 await 表达式会阻塞运行,甚至可以直接阻塞循环,所以整体看起来像同步的代码,也更符合直觉,更容易读懂这个代码。

日常妙用 await

asyncawait 不单可以使用在请求接口上,还可以为代码适当造成"阻塞"。

有时候我们就是想要一些功能函数延迟几秒后执行:

 async function delayTwoFunt() {return new Promise((resolve) => {setTimeout(() => {resolve("2m,");}, 2000);});}async function firstFunt() {console.log("start");const delayRes = await delayTwoFunt();console.log("delayRes: ", delayRes);console.log("firstFunt");}firstFunt(); 

小心 await 阻塞

由于 await 能够阻塞 async 函数的运行,所以代码看起来更像同步的代码,更容易阅读和理解。但是要小心 await 阻塞,因为有些阻塞是不必要的,不恰当使用可能会影响代码的性能。

假如我们要把一个网络数据和本地数据合并,错误的实例可能是这样子:

 async function combineData(url, file) {let networkData = await fetch(url);let fileData = await readeFile(file);console.log(networkData + fileData);} 

其实我们不用等一个文件读完了,再去读下个文件,我们可以两个文件一起读,读完之后再进行合并,这样能提高代码的运行速度。我们可以这样写:

 async function combineData(url, file) {let fetchPromise = fetch(url);let readFilePromise = readFile(file);let networkData = await fetchPromise;let fileData = await readFilePromise;console.log(networkData + fileData);} 

这样的话,就可以同时 网络请求 和 读取文件 了,可以节省很多时间。这里主要是利用了 Promise 一旦创建就立刻执行的特点,如果你熟悉 Promise 的话,可以直接使用 Promise.all 的方式来处理,或者 await 后面跟 Promise.all

以下代码的执行顺序是?

 async function foo() {console.log(1);await bar();console.log(2);}async function bar() {console.log(3);}foo();console.log(4);//1342 

过程分析:

  • 首先一进来是创建了两个函数的,我们先不看函数的创建位置,而是看它的调用位置
  • 发现 foo 函数被调用了,然后去看看调用的内容
  • 执行函数中的同步代码log(1),之后碰到了 await ,它会阻塞foo后面代码的执行,因此会先去执行 bar 中的同步代码,然后 跳出 foo
  • 跳出 foo 函数后,执行同步代码 log(4)
  • 在一轮宏任务全部执行完之后,再来执行刚刚 await 后面的内容 log(2)。

在这里,你可以理解为「紧跟着await后面的语句相当于放到了 new Promise 中,下一行及之后的语句相当于放在 Promise.then中」。

让我们来看看将await转换为 Promise.then 的伪代码:

 async function foo() {console.log(1);// 原来代码// await bar();// console.log(2);// 转换后代码new Promise((resolve) => {resolve();bar();}).then((res) => console.log(2));}async function bar() {console.log(3);}foo();console.log(4);//1342// 复制代码转换后的伪代码和前面的执行结果是一样的。 

异常处理

try...catch

async 函数中,异常处理一般是 try...catch ,如果没有进行 try...catchawait 表达式一旦 rejectasync 函数返回的 Promise 就会 reject

其实结合 Promise 来看,如果一个 Promise 状态敲定为 reject ,并且后续的 then 没有传入 reject 函数,或者没有 catch ,那么就会抛出异常。从这个角度来看,在 async 函数中用 try...catch 来包住 await 表达式,可能就是 catch 住这个异常,并且把这个 reject 信息传到 catch 里面。

这里就不举例子了。

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

3. 无重复字符的最长子串(滑动窗口)

文章目录题目描述暴力破解滑动窗口优化知识积累待解决题目描述 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输…

python 操作符介绍

python操作符分类:算数操作符;比较操作符;逻辑操作符;成员操作符;身份操作符; 1 算数操作符: 常用的算数操作符:; python如何执行除法: 许多编程语言中整数除法执行的…

另一半人马座,孟庭苇

我写过生于12月25日的半人马座桂纶镁《半人马座,桂纶镁》。射手座是11月23日-12月21日。而摩羯座的开始恰恰是:12月22日。而孟庭苇,恰恰就生于12月22日。她更是半人马座啊。1989年,20岁的孟庭苇出演铃木机车广告出道(没…

分享一套响应式自适应公司网站官网源码,带文字搭建教程

分享一套响应式自适应公司网站官网源码,带文字搭建教程。需要源码学习可私信我。 技术架构 PHP7.2 nginx mysql5.7 JS CSS HTML cnetos7以上 宝塔面板 系统介绍 1、四网合一企业网站管理系统支持在线升级(支持跨版本)、插件在线安装、系…

跳表SkipList介绍与实现

目录 一.跳表介绍 二.实现思路 (一).结点结构 (二).检索 (三).插入 (四).删除 三.实现代码 一.跳表介绍 跳表是一种随机化数据结构,主要用于快速检索数据。实质上…

JavaScript 函数

文章目录JavaScript 函数JavaScript 函数语法调用带参数的函数带有返回值的函数局部 JavaScript 变量全局 JavaScript 变量JavaScript 变量的生存期向未声明的 JavaScript 变量分配值笔记列表JavaScript 函数 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。 实…

Go语言之容器总结

目录 1.值类型 1.1. 数组Array 数组遍历 数组初始化 值拷贝 内置函数len、cap 2. 引用数据类型 2.1. 切片slice 切片初始化 切片的内存布局 通过slice修改struct array值 用append内置函数操作切片(切片追加) slice自动扩容 slice中cap重新…

基于yolov5算法的安全帽头盔检测源码+模型,Pytorch开发,智能工地安全领域中头盔目标检测的应用

基于yolov5算法的安全帽头盔检测|Pytorch开发源码模型 本期给大家打开的是YOLOv5在智能工地安全领域中头盔目标检测的应用。 完整代码下载地址:基于yolov5算法的安全帽头盔检测源码模型 可视化界面演示: 💥💥💥新增…

opencv c++ Mat CUDA的编译与使用

Mat 构造函数 cv::Mat img ; //默认 定义了一个Mat img cv::imread("image.jpg");//除了直接读取,还有通过大小构造等cv::Mat img cv::imread("image.png", IMREAD_GRAYSCALE); cv::Mat img_novel img;转换 Mat::convertTo(Mat& m, in…

【自学Java】Java方法

Java方法 Java方法教程 在 Java 语言 中,方法就是一段可重复调用的代码段。在平时开发直接交流中,也有一些同学喜欢把方法叫做函数,这两个其实是一个概念。 Java语言方法详解 语法 public void fun(Object param1,...){//do something }…

多线程与高并发(四)

【Exchanger】&#xff1a; package Ten_Class.t04.no139;import java.util.concurrent.Exchanger;public class T12_TestExchanger {static Exchanger<String> exchanger new Exchanger<>();public static void main(String[] args) {new Thread(() -> {Stri…

实验二十四 策略路由配置

实验二十四 策略路由配置实验要求&#xff1a; 某企业通过路由器AR1连接互联网&#xff0c;由于业务儒要&#xff0c;与两家运营商ISPA和ISPB相连。 企业网内的数据流从业务类型上可以分为两类&#xff0c; 一类来自于网络172.16.0.0/16&#xff0c;另 一类 来自于网络172.17.0…

百趣代谢组学分享:黑木耳多糖对小鼠肠道微生物及代谢表型的影响

文章标题&#xff1a;Effects of Auricularia auricula Polysaccharides on Gut Microbiota and Metabolic Phenotype in Mice 发表期刊&#xff1a;Foods 影响因子&#xff1a;5.561 作者单位&#xff1a;西北大学 百趣提供服务&#xff1a;发现代谢组学Standard-亲水版、1…

dataCompare大数据对比之异源数据对比

在从0到1介绍一下开源大数据比对平台dataCompare 已经详细介绍了dataCompare 的功能&#xff0c;目前dataCompare 已经实现同源数据的对比 一、dataCompare 现有核心功能如下&#xff1a; (1)数量级对比 (2)一致性对比 (3)差异case 自动发现 (4)定时调度自动对比数据 二、…

【个人解答版】笔试题-2023禾赛-FPGA

题目背景 笔试时间&#xff1a;2022.06.22应聘岗位&#xff1a;FPGA开发工程师 题目评价 难易程度&#xff1a;★★☆☆☆知识覆盖&#xff1a;★☆☆☆☆超纲范围&#xff1a;☆☆☆☆☆值得一刷&#xff1a;★☆☆☆☆ 文章目录1. 使用最少的电路实现二分频&#xff0c;给出…

《机器学习实战》chap1 机器学习概览

《机器学习实战》chap1 机器学习概览 Chap1 The Machine Learning Landscape 这本书第三版也已经出版了:https://github.com/ageron/handson-ml3 Hands-on Machine Learning with Scikit-Learn,Keras & TensorFlow 引入 很早的应用&#xff1a;光学字符识别(OCR&#xff0…

远程办公之怎样在外网登录在线答题网站

很多学校或企业因为教学、测试需要&#xff0c;为学生或员工提供了在线答题平台网站&#xff0c;但弊端是这种在线答题平台只能在校内或在企业内网访问使用&#xff0c;在外网是无法登录访问的。在无公网Ip服务器上部署的web&#xff0c;默认情况下只能内网访问&#xff0c;公网…

TLE4943C/CH505C轮速传感器芯片的输出协议介绍

Infineon公司的TLE4943是一款集成式有源磁场传感器&#xff0c;适用于基于霍尔技术的车轮速度应用。它的基本功能是测量磁极轮或铁磁齿轮的速度。它具有使用AK协议进行通信的两线电流接口。该协议除了提供速度信号外&#xff0c;还提供其他信息&#xff0c;如车轮旋转方向和气隙…

java安装教程-windows

检查是否已经安装过jav打开cmd命令窗口 输入 java -v下载java安装包网址&#xff1a;https://www.oracle.com/java/technologies/downloads/安装java双击运行程序jdk-19_windows-x64_bin.exe&#xff0c;点击下一步进行安装可以更改安装路径&#xff0c;注意安装路径不能有中文…

【TypeScript】TS类型守卫(六)

&#x1f431;个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️作者简介&#xff1a;前端领域新星创作者、华为云享专家、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff…