6.Vue------async/await详细的讲解---知识积累
前提:
先说一下Promise解释
Promise是一种在JavaScript中处理异步操作的对象。它代表了一个尚未完成但承诺未来某个时间会完成的操作结果。Promise有三种状态:pending(等待中)、fulfilled(已成功)和rejected(已失败)。当一个Promise创建后,它可以转换到这三种状态之一,并触发对应的回调函数。
.then()方法用于注册成功处理函数,如果Promise解析(fulfillment),这个函数会被调用并传入解析后的值。
.catch()方法则用于注册错误处理函数,当Promise被拒绝(rejection)时,这个函数会被调用,接收拒绝的原因。
使用.finally()可以在无论Promise是否成功都会执行的代码块,通常用于清理工作。
通过链式调用then和catch,可以使异步代码看起来更像同步代码,提高了代码的可读性和维护性。例如:
let promise = someAsyncFunction();
promise.then(result => {// 成功处理
}).catch(error => {// 失败处理
}).finally(() => {// 执行最终清理
});
正文:
我的理解:
- async的作用是定义这个函数是异步:async 放在函数前的一个关键字,再函数内 return 1、return "1"、return new Promise(),外部打印这个函数都是获取到的是一个promise对象,通过函数.then获取到return的值。
- await的作用是等待 : 如果等待的不是promise对象他不会阻塞后面的代码,反之他等待的是一个promise对象 则会阻塞后面的代码,用await在前面做修饰他会直接得到resolve里面是数据,这就是await的工作。
一、async 和 await 在干什么
- async 是“异步”的简写,而 await 的意思是等待。
- async 用于申明一个 function 是异步的,而 await 等待某个操作完成。
- async/await 是一种编写异步代码的新方法。之前异步代码的方案是回调和 promise。
- async/await 像 promise 一样,也是非阻塞的。
- async/await 让异步代码看起来、表现起来更像同步代码。这正是其威力所在。
二、async 起什么作用
这个问题的关键在于,async 函数是怎么处理它的返回值的!
我们当然希望它能直接通过 return 语句返回我们想要的值,但是如果真是这样,似乎就没 await 什么事了。所以,写段代码来试试,看它到底会返回什么:
<script> async function test(){return 'hello async';}let result = test();console.log(result);
</script>
输出的是一个 Promise 对象
所以,async 函数返回的是一个 Promise 对象。async 函数(包含函数语句、函数表达式、Lambda表达式)会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
async 函数返回的是一个 Promise 对象,所以在最外层不能用 await 获取其返回值的情况下,我们当然应该用原来的方式:then() 链来处理这个 Promise 对象,就像这样
async function test(){return 'hello async';}test().then((val) => {console.log(val); //hello async })
现在回过头来想下,如果 async 函数没有返回值,又该如何?很容易想到,它会返回 Promise.resolve(undefined)。
联想一下 Promise 的特点——无等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。
那么下一个关键点就在于 await 关键字了。
三、await 到底在等啥
因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,但要清楚,它等的实际是一个返回值。注意到 await 不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。所以下面这个示例完全可以正确运行。
function getSomething(){return "something";
}
async function testAsync(){return Promise.resolve('hello async');
}
async function test(){let v1 = await getSomething();let v2 = await testAsync();console.log(v1,v2);
}
test();
console.log('我执行了');//执行结果为:
//我执行了
//something,hello async
await 等到了要等的,然后呢
await 等到了它要等的东西,一个 Promise 对象,或者其它值,然后呢?我不得不先说,await 是个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西。
如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。
如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。
看到上面的阻塞一词,心慌了吧……放心,这就是 await 必须用在 async 函数中的原因。async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。
四、作个简单的比较
then 链处理
function takeLongTime(){return new Promise((resolve) => {setTimeout(() => resolve('long time value'),1000);})
}
takeLongTime().then((v) => {console.log('get:',v);
})
如果改用 async/await 呢,会是这样。
function takeLongTime(){return new Promise((resolve) => {setTimeout(() => resolve('long time value'),1000);})
}
async function test(){let v = await takeLongTime();//等待异步操作的结果,阻塞后面代码的执行console.log(v);
}
假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout 来模拟异步操作:
a.同步代码执行对比
/** 传入参数n,表示这个函数执行的时间(毫秒)* 执行的结果是 n+200,这个值将用于下一步骤
*/
function takeLongTime(n){return new Promise((resolve) => {setTimeout(() => resolve(n + 200),n);})
}
function step1(n){console.log(`step1 with ${n}`);return takeLongTime(n);
}
function step2(n){console.log(`step2 with ${n}`);return takeLongTime(n);
}
function step3(n){console.log(`step3 with ${n}`);return takeLongTime(n);
}//1.现在用 Promise 方式来实现这三个步骤的处理(then链式)。function doIt(){console.time('doIt');let time1 = 300;step1(time1).then((time2) => step2(time2)).then((time3) => step3(time3)) .then((result) => {console.log(`result is ${result}`);console.timeEnd("doIt");})
}doIt();//执行结果为:
//step1 with 300
//step2 with 500
//step3 with 700
//result is 900
//doIt: 1510.2490234375ms/*总结:输出结果 result 是 step3() 的参数 700 + 200 = 900。doIt() 顺序执行了三个步骤,一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 计算的结果一致。*/// 2.用 async/await 来实现呢,会是这样async function doIt() {console.time('doIt');let time1 = 300;let time2 = await step1(time1);//将Promise对象resolve(n+200)的值赋给time2let time3 = await step1(time2);let result = await step1(time3);console.log(`result is ${result}`);console.timeEnd('doIt');
}doIt();//执行结果为:
//step1 with 300
//step2 with 500
//step3 with 700
//result is 900
//doIt: 1512.904296875ms
b.现在把业务要求改一下,仍然是三个步骤,但每一个步骤都需要之前每个步骤的结果
/** 传入参数n,表示这个函数执行的时间(毫秒)* 执行的结果是 n+200,这个值将用于下一步骤
*/
function takeLongTime(n){return new Promise((resolve) => {setTimeout(() => resolve(n + 200),n);})
}
function step1(n){console.log(`step1 with ${n}`);return takeLongTime(n);
}
function step2(m,n){console.log(`step2 with ${m} + ${n}`);return takeLongTime(m + n);
}
function step3(k,m,n){console.log(`step3 with ${k} + ${m} + ${n}`);return takeLongTime(k + m + n);
}// 1.这回先用 async/await 来写:async function doIt() {console.time('doIt');let time1 = 300;let time2 = await step1(time1);//将Promise对象resolve(n+200)的值赋给time2let time3 = await step2(time2,time1);let result = await step3(time3,time2,time1);console.log(`result is ${result}`);console.timeEnd('doIt');
}doIt();//执行结果为:
//step1 with 300
//step2 with 500 + 300
//step3 with 1000 + 500 + 300
//result is 2000
//doIt: 2916.655029296875ms// 2.用 Promise 方式实现(then链式)function doIt() {console.time('doIt');let time1 = 300;step1(time1).then((time2) => {return step2(time1,time2).then((time3) => [time1,time2,time3])//step3需要用到time1,time2,time3,因此需要返回}).then((times) => {let [time1,time2,time3] = times;return step3(time1,time2,time3)}).then((result) => {console.log(`result is ${result}`);console.timeEnd('doIt');})
}doIt();//执行结果为:
//step1 with 300
//step2 with 300 + 500
//step3 with 300 + 500 + 1000
//result is 2000
//doIt: 2919.49609375ms
五、注意点
就目前来说,已经理解 async/await 了吧?但其实还有一些事情没提及——Promise 有可能 reject 啊,怎么处理呢?
await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在try...catch 代码块中。
async function myFunction() {try {await somethingThatReturnAPromise();} catch (err){console.log(err);}
}//另一种写法
async function myFunction() {await somethingThatReturnAPromise().catch(function(err) {console.log(err);})
}
六、实例
1、异步:如我希望以下代码按照第一、二、三、四步的顺序执行:
export default {name: 'Default',data() {return {id: ''};},created() {this.init();},methods: {init() {//第一步let res = this.getReportId();//第四步this.id = res;alert('4:' + this.id);},getReportId(scene) {let id = '';this.$api['report/getMyReports']({roleId:'gly'}).then(data => {if (data && data.length > 0) {//第二步id = data[0].reportId;alert('2:' + id);}});//第三步alert('3:' + id);return id;}}
};
</script>
执行的结果却是:
可以看到,ajax请求最后执行,其他部分按顺序先执行了。可以修改下ajax的return顺序再验证下这个结论:
<script>
export default {name: 'Default',data() {return {id: ''};},created() {this.init();},methods: {init() {//第一步let res = this.getReportId();//第四步this.id = res;alert('4:' + this.id);},getReportId(scene) {this.$api['report/getMyReports']({scene: 7,roleId: -1}).then(data => {if (data && data.length > 0) {//第二步alert('2:' + data[0].reportId);return data[0].reportId;}});}}
};
</script>
执行顺序:
这会导致我在最后一步(第四步)获取的结果不准确。常用的解决方法是把第四步的赋值操作放到第二步中,即接口响应数据了再赋值。下面用另一种方法,代码同步方法来实现:
2、ajax请求同步方法:
<script>
export default {name: 'Default',data() {return {id: ''};},created() {this.getReportIds();},methods: {getReportIds() {let _this = this;//第一步this.getReportId().then(function(result) {//第四步_this.id = result;alert('4:' + _this.id);});},async getReportId(scene) {let id = '';await this.$api['report/getMyReports']({roleId: 'gly'}).then(data => {if (data && data.length > 0) {//第二步id = data[0].reportId;alert('2:' + id);}});//第三步alert('3:' + id);return id;}}
};
</script>
执行结果:
相关文章:

6.Vue------async/await详细的讲解---知识积累
前提: 先说一下Promise解释 Promise是一种在JavaScript中处理异步操作的对象。它代表了一个尚未完成但承诺未来某个时间会完成的操作结果。Promise有三种状态:pending(等待中)、fulfilled(已成功)和reject…...

Redis面试专题-持久化
目录 前言 持久化相关知识 1.三种持久化机制 2.RDB持久化 3.深入剖析一下RDB持久化过程 4.AOF持久化 5.RDB和AOF对比编辑 面试题 1.redis持久化机制有哪些? 2.那仔细讲讲你对他们的理解 3.你刚刚说AOF的文件很大,那AOF文件会越来越大…...

如何将快捷指令添加到启动台
如何将快捷指令添加到启动台/Finder/访达(Mac) 1. 打开快捷指令创建快捷指令 示例创建了一个文件操作测试的快捷指令。 2. 右键选择添加到程序坞 鼠标放在待添加的快捷指令上。 3. 右键添加到访达 鼠标放在待添加的快捷指令上。 之后就可以在启…...

ansible自动化运维(二)ad-hoc模式
目录 Ansible模块(ad-hoc模式) 1.command模块:远程执行命令 2.shell 模块:远程执行命令,支持管道,重定向 3.Raw模块:先登录,再执行,最后退出 4.Script模块ÿ…...

技术栈6:Docker入门 Linux入门指令
目录 1.Linux系统目录结构 2.处理目录的常用命令 3.Docker概述 4.Docker历史 5.Docker基本组成 6.Docker底层原理 7.Docker修改镜像源 8.Docker基本命令 9.Docker创建Nginx实战 10.数据卷 11.本地目录直接挂载* 12.镜像和dockerfile 13.容器互联与自定义网络 14.…...

OPStack Optimism Layer2
概述 OP Stack 是标准化、共享和开源的开发堆栈,为 Optimism 提供支持,由 Optimism Collective 维护。 Optimism Bedrock 是 OP Stack的当前版本。 Bedrock 版本提供了用于启动生产质量的 Optimistic Rollup 区块链的工具。此时,OP Stack不同层的 API 仍然与Stack的 Rollu…...

Leetcode—1498. 满足条件的子序列数目【中等】
2024每日刷题(210) Leetcode—1498. 满足条件的子序列数目 C实现代码 class Solution { public:int numSubseq(vector<int>& nums, int target) {const int MOD 1e9 7;int n nums.size();vector<int> pows(n, 1);for(int i 1; i &…...

生活大爆炸版石头剪刀布(洛谷P1328)
生活大爆炸版石头剪刀布(洛谷P1328) [NOIP2014 提高组] 前言: 由于洛谷发布题解有限制,所以在CSDN上发布洛谷题解。 所有题解均是Java语言, 但是思路是相同的 每篇都是刷题日常,尽量讲清楚算法逻辑。 希望有问题还请大佬们指导! …...

OmniParser一种用于增强视觉语言模型与用户界面交互效果的技术
OmniParser一种用于增强视觉语言模型与用户界面交互效果的技术 OmniParser的核心功能是将用户界面截图转换为结构化元素,这一过程涉及几个关键步骤和技术要素,解决了视觉语言模型(VLMs)在与用户界面交互时所面临的多种挑战。 1.…...

Unity引擎UI滚动列表——滚动复用基础介绍
大家好,我是阿赵。 一、滚动复用的介绍 在制作游戏的过程中,经常会遇到一些需要显示数量比较大的数据的情况。比如说,一个排行榜,需要展示当前服务器前一千个玩家的排名。或者游戏的背包容量特别大,可以有几千个格子。…...

在 Windows 11 WSL (Ubuntu 24.04.1 LTS) | Python 3.12.x 下部署密码学库 charm
1. 在 Windows 11 上部署 Ubuntu (WSL) 由于作者没有高性能的 Ubuntu 服务器或个人电脑,且公司或学校提供的 Ubuntu 服务器虽然提供高性能 GPU 等硬件配置但通常不会提供 root 权限,因而作者通过在搭载了 Windows 11 的个人电脑上启动 Ubuntu (WSL) 来进…...

【六足机器人】01功能开发
包含:WIFI模块、GPS模块、语言模块、调试信息接口。 一、硬件连接 huart4( PA0、 PA1 )与GPS模块连接。 huart3(PB10、PB11)与ESP8266模块连接。 huart2( PA2、 PA3 )与语音模块连接。 hu…...

notepad++安装教程(超详细)
1.下载地址(可以私信博主) https://notepad-plus.en.softonic.com/download 2.解压安装...

创建简单的 PL/pgSQL 存储过程
文章目录 创建简单的 PL/pgSQL 存储过程CREATE OR REPLACE FUNCTIONadd_two_numbers(a integer, b integer)RETURNS integerAS$$ ... $$函数体LANGUAGE plpgsql 创建带有 IN 和 OUT 参数的存储过程创建修改数据的存储过程创建带有异常处理的复杂存储过程 在 PostgreSQL 中&…...

Java项目实战II基于微信小程序的无中介租房系统(开发文档+数据库+源码)
目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着城市化进程的加速,租房市场日益繁荣&a…...

Node.js实现WebSocket教程
Node.js实现WebSocket教程 1. WebSocket简介 WebSocket是一种在单个TCP连接上提供全双工通信的协议,允许服务器和客户端之间进行实时、双向通信。本教程将详细讲解如何在Node.js中实现WebSocket。 2. 技术选型 我们将使用ws库来实现WebSocket服务器,…...

Docker Compose实战一( 轻松部署 Nginx)
通过过前面的文章(Docker Compose基础语法)你已经掌握基本语法和常用指令认识到Docker Compose作为一款强大工具的重要性,它极大地简化了多容器Docker应用程序的部署与管理流程。本文将详细介绍如何使用 Docker Compose 部署 Nginx࿰…...

hive分区分桶、数据倾斜总结
一、hive的基本概念 hive是一个构建在hadoop上的数据仓库工具,可以将结构化的数据文件映射为一张数据库表并提供数据查询功能 二、hive的特点 (1)数据是存储在hdfs上 (2)底层是将sql转换为MapReduce任务进行计算 …...

unity打包到安卓帧率降低
这个问题遇到过很多次了我的做法就是直接设置Application.targetFrameRate60 参考...

【Python3】装饰器 自动更新缓存
自动更新缓存的需求场景 在某些应用中,我们可能需要定期从外部数据源(如 Redis 或者远程接口)拉取数据,并将其缓存在内存中。当有其他代码需要访问这些数据时,可以立刻从内存获取最新数据,而无需每次都进行…...

通过EPEL 仓库,在 CentOS 7 上安装 OpenResty
通过EPEL 仓库,在 CentOS 7 上安装 OpenResty 通过EPEL 仓库,在 CentOS 7 上安装 OpenResty步骤 1: 安装 EPEL 仓库步骤 2: 安装 OpenResty步骤 3: 启动 OpenResty步骤 4: 设置开机自启步骤 5: 验证安装说明 通过EPEL 仓库,在 CentOS 7 上安装…...

[RabbitMQ] RabbitMQ常见应用问题
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...

每日速记10道java面试题13-MySQL篇
其他资料 每日速记10道java面试题01-CSDN博客 每日速记10道java面试题02-CSDN博客 每日速记10道java面试题03-CSDN博客 每日速记10道java面试题04-CSDN博客 每日速记10道java面试题05-CSDN博客 每日速记10道java面试题06-CSDN博客 每日速记10道java面试题07-CSDN博客 每…...

乐鑫科技嵌入式面试题及参考答案(3万字长文)
嵌入式开发为什么用 C 语言,而不用 C++ 语言? 在嵌入式开发中,C 语言被广泛使用而 C++ 相对少用有以下一些原因。 首先,C 语言具有更高的效率。嵌入式系统通常资源受限,包括处理器速度、内存容量等。C 语言的代码生成效率高,能够生成紧凑的机器码,占用较少的内存空间和处…...

Leetcode 每日一题 56.合并区间
目录 问题描述 示例 示例 1 示例 2 问题分析 算法设计 步骤 1:排序 步骤 2:合并区间 步骤 3:返回结果 过题图片 代码实现 复杂度分析 题目链接 结语 问题描述 给定一个区间数组 intervals,其中每个区间由两个整数 s…...

【Vue】v-model、ref获取DOM
目录 v-moel v-model的原理 v-model用在组件标签上 方式 defineModel()简写 ref属性 获取原生DOM 获取组件实例 nextTick() v-moel v-model:双向数据绑定指令 数据变了,视图跟着变(数据驱动视图)视图变了,数…...

Python 类的设计(以植物大战僵尸为例)
关于类的设计——以植物大战僵尸为例 一、设计类需满足的三要素1. 类名2. 属性和方法 二、以植物大战僵尸的为例的类的设计1. 尝试分类2. 创建对象调用类的属性和方法*【代码二】*3. 僵尸的继承 三、代码实现 一、设计类需满足的三要素 1. 类名 类名:某类事物的名…...

python中权重剪枝,低秩分解,量化技术 代码
目录 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 低秩分解 scipy 量化技术 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 权重剪枝可以通过PyTorch的torch.nn.utils.prune模块实现。以下是一个简单的例子: import torch import torch.nn as nn impor…...

调用matlab用户自定义的function函数时,有多个输出变量只输出第一个变量
很多朋友在使用matlab时,会使用或自己编辑多个function函数,来满足自己对任务处理的要求,但是在调用function函数时,会出现这个问题:调用matlab用户自定义的function函数时,有多个输出变量只输出第一个变量…...

RabbitMQ七种工作模式之简单模式, 工作队列模式, 发布订阅模式, 路由模式, 通配符模式
文章目录 一. Simple(简单模式)公共代码:生产者:消费者: 二. Work Queue(工作队列模式)公共代码:生产者:消费者1, 消费者2(代码相同): 三. Publish/Subscribe(发布/订阅模式)公共代码:生产者:消费者: 四. Routing(路由模式)公共代码:消费者: 五. Topics(通配符模式)公共代码:生…...