【11】ES6:async/await

一、概念

async/await 是 ES2017(ES8)的新特性,它是一种基于 Promise 实现的异步编程方式。async/await 也是一种语法糖。

1、async/await 实现了用同步方式来写异步代码(promise是链式调用形式写异步代码)

2、async 是“异步” 的简写,用来声明一个 function 是异步的

3、await 是 async wait 的简写,用于等待一个异步方法执行完成

4、await 只能出现在 async 函数中

二、async 函数

1、基本使用

在函数声明前添加 async 关键字,表示该函数是异步的。

async 函数的返回值是一个 Promise 对象。 async 函数返回的值可以通过 then() 方法回调函数的参数或者 await 表达式获取。

async 函数内部使用 return 语句返回的值会被自动封装成 Promise 对象,并且该对象的状态会根据 return 语句返回的值类型自动变为 resolved 或 rejected。

async function foo() {return 'Hello World!'
}foo().then(value => console.log(value))
// 'Hello World!'
async function bar() {throw new Error('Something went wrong!')
}bar().catch(error => console.error(error)) 
// 'Error: Something went wrong!'

如果 async 函数中没有 return 语句,则该函数返回一个 undefined 值的 Promise 对象。

async function foo() {const result = await Promise.resolve('Hello World!')console.log('Hello World!')// 等同于 return Promise.resolve(undefined)
}foo().then(value => console.log(value)) 
// 'Hello World!'
// undefined

拓展知识:
如果在async 函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
Promise.resolve(x) 可以看作是 new Promise(resolve => resolve(x)) 的简写,可以用于快速封装字面量对象或其他对象,将其封装成 Promise 实例。

暂停和恢复执行: 在async 函数内部,可以使用 await 关键字来等待一个 Promise 对象的状态改变。当遇到 await 时,函数会暂停执行,并等待 Promise 对象的状态变为 resolved 或 rejected,然后恢复执行。

async function foo() {console.log('开始执行')await new Promise(resolve => setTimeout(resolve, 2000)) // 等待2秒钟console.log('2秒钟后恢复执行')return '完成'
}console.log('调用函数')foo().then(value => {console.log('异步函数返回值:', value)
})console.log('继续执行')// 调用函数
// 开始执行
// 继续执行
// 2秒钟后恢复执行
// 异步函数返回值: 完成

在上面的示例中,我们定义了一个 foo 的 async 函数。首先在主线程中调用 foo 函数,然后输出开始执行和继续执行。接下来,我们使用 await 关键字等待一个 2 秒钟后 resolved 的 Promise 对象。在等待期间,函数会暂停执行,并且主线程可以继续执行其他代码。当 2 秒钟过去后,Promise 对象的状态变为 resolved,await 表达式会返回 resolved 的值(在此例中为 undefined),并且函数恢复执行,输出 2 秒钟后恢复执行。最后,foo 函数返回一个 resolved 状态的 Promise 对象,该对象的值为’完成’。在 then 方法的回调函数中,我们打印出异步函数的返回值完成。

2、async 函数的多种使用形式

// 函数声明
async function foo() {}// 函数表达式
const foo = async function () {}// 对象的方法
let obj = { async foo() {} }
obj.foo().then(...)// Class 的方法
class Storage {constructor() {this.cachePromise = caches.open('avatars')}async getAvatar(name) {const cache = await this.cachePromisereturn cache.match(`/avatars/${name}.jpg`)}
}const storage = new Storage()
storage.getAvatar('jake').then()// 箭头函数
const foo = async () => {}

三、await 命令

await 只能在 async 函数内部使用,它会暂停 async 函数的执行,等待 Promise 对象的状态改变,然后再继续执行 async 函数。

正常情况下,await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。(promise 对象、async 函数、普通数据)

async function f() {// 等同于 return 123return await 123
}f().then(v => console.log(v))
// 123

错误处理 与 try…catch 使用

await 命令后面的 Promise 对象如果变为 reject 状态,则 reject 的参数会被 catch 方法的回调函数接收到。

async function f() {await Promise.reject('出错了')
}f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了

任何一个 await 语句后面的 Promise 对象变为 reject 状态,那么整个 async 函数都会中断执行。

async function f() {await Promise.reject('出错了')await Promise.resolve('hello world') // 不会执行
}

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个 await 放在 try…catch 结构里面,这样不管这个异步操作是否成功,第二个 await 都会执行。

async function f() {try {await Promise.reject('出错了')} catch(e) {}return await Promise.resolve('hello world')
}f().then(v => console.log(v))
// hello world

另一种方法是 await 后面的 Promise 对象再跟一个 catch 方法,处理前面可能出现的错误。(了解)

async function f() {await Promise.reject('出错了').catch(e => console.log(e))return await Promise.resolve('hello world')
}f().then(v => console.log(v))
// 出错了
// hello world

如果有多个 await 命令,可以统一放在 try…catch 结构中。

async function main() {try {const val1 = await firstStep()const val2 = await secondStep(val1)const val3 = await thirdStep(val1, val2)console.log('Final: ', val3)} catch (err) {console.error(err)}
}

四、async/await 与 promise 比较

async/await 是一种更加直观、简洁且易读的异步处理方式,适合处理复杂的异步操作流程和错误处理。而 promise 则更加底层,可以用于更细粒度的异步控制和组合操作。在实际开发中,可以根据具体的需求和场景选择合适的异步处理方式。

语法差异

promise 是基于回调函数的异步处理方式,使用 then 和 catch 方法来处理异步操作的结果和错误。

async/await 是一种基于生成器函数(Generator)和 promise 的语法糖,通过在函数前面加上 async 关键字,将函数转换为返回 promise 对象的异步函数,并使用 await 关键字等待异步操作的结果。

可读性

promise 以链式调用的形式书写异步代码。

async/await 以同步形式书写异步代码。更加直观和易读,代码结构更加清晰。

错误处理

promise 中,通常使用 catch 方法来捕获和处理错误。

async/await 中,通常使用 try…catch 语句来捕获和处理错误。

异步操作的顺序

promise 中,如果有多个异步操作需要按照特定的顺序执行,我们需要通过嵌套的 then 方法或使用 Promise.all、Promise.race 等组合方法来实现。

async/await 中,可以使用同步的代码风格来编写异步操作的顺序,使代码更加简洁和可读。

错误堆栈

promise 中,当发生错误时,错误信息中会包含详细的堆栈信息,可以追踪到错误发生的位置。

async/await 中,由于使用了 try…catch 语句捕获错误,堆栈信息可能会被截断,不够详细。

function fetchUser(userId) {return new Promise((resolve, reject) => {setTimeout(() => {if (userId === 1) {resolve({ id: userId, name: 'Alice' })} else {reject(new Error('User not found'))}}, 1000)})
}// 使用 Promise 实现异步操作
fetchUser(1).then(user => console.log(user)).catch(error => console.error(error))// 使用 async/await 实现异步操作
async function getUser(userId) {try {const user = await fetchUser(userId)console.log(user)} catch (error) {console.error(error)}
}
getUser(1)

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

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

相关文章

【JavaScript】闭包机制

✨ 专栏介绍 在现代Web开发中,JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性,还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言,JavaScript具有广泛的应用场景&#x…

java设计模式学习之【解释器模式】

文章目录 引言解释器模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用表达式解析示例代码地址 引言 在我们的日常生活中,语言的翻译和理解是沟通的关键。每种语言都有自己的语法规则,而翻译人员和计算机程序需要理解并遵循这些规则来…

LeetCode75| 队列

目录 933 最近的请求次数 649 Dota2 参议院 933 最近的请求次数 class RecentCounter { public:queue<int>st;RecentCounter() {}int ping(int t) {st.push(t);while(t - st.front() > 3000)st.pop();return st.size();} };时间复杂度O(1) 空间复杂度O(n)//n为队列…

手写Promise

目录 前言 状态 使用方法 构造函数 对象 结论 第一阶段 搭建基本结构 思路 代码实现 测试一下 实现then方法获取异步值 思路 改造代码如下 测试一下 成功场景 失败场景 实现类的resolve,reject以及catch方法 思路 代码实现 测试一下 第一阶段总结 第二阶…

《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识(11)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第I篇 第1章 PCI总线的基本知识&#xff08;10&#xff09; 1.3 PCI总线的存储器读写总线事务 1.3.2 Posted和Non-Posted传送方式 PCI总线规定了两类数据传送方式&#xff0c;分别是Posted和Non-Posted数据传送…

关于Redis面试题

前言 之前为了准备面试&#xff0c;收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文&#xff1a;https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv Redis 是什么 全名&#xff1a;远程字典服务。这是一个开源的在内存中的数据结构存…

硅像素传感器文献调研(二)

写在前面&#xff1a;从上篇文章的参考文献中看到一篇文献&#xff0c;现在也精读一下&#xff0c;今天还有一个任务是把上篇文献整体脉络用流程图的形式完整梳理一下。 哈哈哈哈哈哈&#xff1a;代表没太搞明白的部分 如何写论文&#xff1a; 引言部分&#xff1a;基础理论…

vue3 引入腾讯地图解决请求接口https://apis.map.qq.com/ws/place/v1/suggestion跨域问题

试过npm i vue-jsonp不行&#xff0c;然后重新试了这个办法解决了 index.html 中引入 <script charset"utf-8" src"https://map.qq.com/api/gljs?v1.exp&key自己申请的key"></script> 重写 jsonp&#xff0c;就不用在项目中安装 jsonp …

基于UOS python pyqt5开发声卡回路测试程式

1. 环境准备 首先&#xff0c;确保你的UOS系统中安装了Python和PyQt5。 安装Python&#xff1a;大多数Linux发行版都预装了Python。你可以通过在终端运行 python3 --version 来检查Python版本。 安装PyQt5&#xff1a;通过运行 sudo apt-get install python3-pyqt5 来安装Py…

Python入门知识点分享——(十一)if条件语句

if条件语句是一种编程语言中用于控制程序流程的结构。它根据一个条件的真假来决定执行不同的代码块。 if条件语句通常由if关键字、一个条件表达式和一个代码块组成。条件表达式可以是一个返回布尔值的表达式&#xff0c;如果条件为真&#xff0c;则执行代码块中的代码&#xf…

day30 回溯(06)【今天没做题,简单记录一下日程与感想】

day30 代码随想录 2023.12.28 今天确实事情有些多&#xff0c;项目汇报&#xff0c;还有一个C单子的交付。并且临近考试&#xff0c;本来想着现在晚上十点多打卡学习&#xff0c;但一看&#xff0c;三道有难度的题&#xff0c;时间不够了&#xff0c;直接劝退&#xff0c;所以…

数据库系统原理例题之——数据库系统概述

第一章 数据库系统概述 第一章 数据库系统概述【例题】一 、单选题二 、填空题三 、简答题 【答案&解析】一、单选题二、填空题三、简答题 【延伸知识点】【延伸知识点答案&解析】 第一章 数据库系统概述 【例题】 一 、单选题 1.数据库管理系统的英文缩写是( ) A.D…

01_软件测试

01_软件测试 学习目标 1、能复述软件测试的定义 2、能说出7种测试分类的区别 3、能说出质量模型的重点5项 4、能说出测试流程的6个步骤 5、能说出测试模板8个要素 认识软件及测试 什么是软件 软件&#xff1a;控制计算机硬件工作的工具 软件的基本组成 软件生产过程 什么是软…

vue多条数据渲染(带图片)

我在这用的为接口数据&#xff1a; 先调用接口获取需要的数据: 然后用&#xff1a;data绑定需要渲染的数据&#xff1b;&#xff08;记得包裹在<el-table>标签中&#xff09; 然后以此循环渲染数据&#xff1b;那怎么渲染出来图片呢&#xff1f; 在<el-table-column…

Vue3-25-路由-路由的基本使用

对路由的理解 路由 &#xff1a; 就是前端对页面路径的拦截&#xff0c;根据不同的路径渲染不同的组件&#xff0c; 从而实现单页应用中的页面局部刷新的功能。安装路由依赖 根据使用的不同的包管理工具采用不同的命令&#xff0c; 常见的三种包管理工具和对应的命令如下&…

day44 1228

作业1&#xff1a; #include <iostream>using namespace std;class Person {int *age;string &name; public:Person(int age,string &name):age(new int(age)),name(name){cout << "Person的构造函数" <<endl;}~Person(){delete age;cout…

【Java系列】多线程案例学习——基于阻塞队列实现生产者消费者模型

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习JavaEE的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录…

如何在Mac中设置三指拖移,这里有详细步骤

三指拖移手势允许你选择文本&#xff0c;或通过在触控板上用三指拖动窗口或任何其他元素来移动它。它可以用于快速移动或调整窗口、文件或图像在屏幕上的位置。 然而&#xff0c;这个手势在默认情况下是禁用的&#xff0c;因此在本教程中&#xff0c;我们将向你展示如何在你的…

【C++】字符串常量 与 字符数组 的区别

字符串常量&#xff1a;"abc" 字符数组&#xff1a;char a[3]{a,b,c}; 那么它们相等吗&#xff1f;它们之间的区别是什么呢&#xff1f; 答&#xff1a;不相等 区别在于 字符串常量"abc" 的本质是以空字符\0结尾的字符数组&#xff0c; 而char a[3]{a,b,…

数据库系统原理例题之——SQL 与关系数据库基本操作

SQL 与关系数据库基本操作 第四章 SQL 与关系数据库基本操作【例题】一 、单选题二 、填空题三 、简答题四 、设计题 【答案&解析】一、单选题二、填空题三、简答题四、设计题 【延伸知识点】【延伸知识点答案&解析】 第四章 SQL 与关系数据库基本操作 【例题】 一 、…