JavaScript异步编程:async、await的使用
async 和 await 是在 ECMAScript 2017 (ES7) 中引入的特性,用于处理异步操作。它们允许你以一种更加简洁和同步的方式来编写异步代码。
async 函数表示它会返回一个 Promise,而 await 关键字用于等待一个 Promise 解决。
关于 promise 的详细介绍,请点击浏:《ECMAScript6语法:Promise》
1、使用 async 修饰符函数
async 是一个函数修饰符,用于声明一个函数是异步的。调用 async 函数时,该函数会立即返回一个 Promise 对象,即使函数体内部没有显式返回 Promise,JavaScript 也会自动将函数的结果封装成 Promise 对象。
语法格式:
//使用 async 关键字修饰函数,被修饰的函数,一定返回 Promise 对象
async function asyncFun() {
return "pan_junbiao的博客";
}
//上述代码,相当于
async function asyncFun() {
return new Promise((resolve, reject) => {
resolve("pan_junbiao的博客");
});
}
//打印函数结果:一个 Promise 对象
console.log(asyncFun());
//打印 Promise 对象的值:pan_junbiao的博客
asyncFun().then((result) => console.log(result));
2、使用 await 等待 Promise 结果
await 必须在 async 函数内部使用。它可以让异步代码像同步代码一样执行,等待 Promise 对象解决后再继续执行下一步。await 后面可以接非 Promise 对象(返回该对象的结果)或者 Promise 对象(返回对应的值)。
语法格式:
// 1、使用 async 关键字修饰函数,被修饰的函数,一定返回 Promise 对象
async function asyncFun() {
return new Promise((resolve, reject) => {
//使用定时器,模拟异步效果,等待3秒后,返回结果
setTimeout(() => { resolve("pan_junbiao的博客") }, 3000);
});
}
// 2、使用 await 等待 Promise 执行完成后返回结果(注意:await 必须在 async 函数内部使用)
async function getUserName() {
let userName = await asyncFun();
console.log("用户名称:", userName);
}
// 3、执行方法
getUserName();
执行结果:
3、什么是回调地狱
回调地狱是指在异步编程中,由于多个回调函数嵌套调用,导致代码可读性差、难以维护的情况。
在 JavaScript 中,回调函数常用于处理异步任务,如 AJAX 请求、Promise 执行和事件绑定等。一旦操作完成,JavaScript 引擎会调用回调函数来处理结果。然而,当多个异步操作连续进行,且每个操作都需要在上一个操作完成后才能执行时,就会出现回调地狱。
回调地狱的问题包括:可读性差,错误处理困难,代码维护困难,以及控制流困难。为了解决这些问题,开发者采用了多种方法,包括使用 Promises、Async/Await、Generators 以及功能编程库等。这些方法使得异步代码的编写更加简洁、易读和易于维护。
4、Vue项目实例
【实例】创建 Vue 项目,使用 async、await函数,实现首先获取用户信息,然后根据用户信息中的部门编号,获取部门信息。
(1)创建 Vue 项目
创建 Vue 项目和使用 axios 二次封装实现 Ajax 请求功能,详情请点击浏览文章:《Vue使用axios二次封装、解决跨域问题》
(2)创建 UserInfo.vue 组件
<template>
<h3>基本信息</h3>
<p>用户名称:{{ userInfo.userName }}</p>
<p>博客信息:{{ userInfo.blogName }}</p>
<p>博客地址:{{ userInfo.blogUrl }}</p>
<h3>部门信息</h3>
<p>部门编号:{{ userInfo.departmentCode }}</p>
<p>部门名称:{{ userInfo.departmentName }}</p>
<button @click="getUser(1)">查询用户</button>
</template>
<script setup>
import { getUserInfo } from '@/api/UserApi.js';
import { getDepartmentInfo } from '@/api/DepartmentApi.js';
import { ref } from 'vue';
// 用户信息:使用 ref 定义一个响应式对象
let userInfo = ref({});
// 常规写法:形成“回调地狱”,代码可读性差,维护困难
// function getUser(userId) {
// // 1、获取用户信息
// getUserInfo(userId).then(
// function (result) {
// userInfo.value = result;
// //2、获取部门信息
// getDepartmentInfo(userInfo.value.departmentCode).then(
// function (department) {
// userInfo.value.departmentCode = department.departmentCode;
// userInfo.value.departmentName = department.departmentName;
// }
// );
// }
// );
// }
// 使用 async、await 优化写法,代码简洁,易于维护
async function getUser(userId) {
// 1、获取用户信息
let userResult = await getUserInfo(userId);
userInfo.value = userResult;
//2、获取部门信息
let department = await getDepartmentInfo(userInfo.value.departmentCode);
userInfo.value.departmentCode = department.departmentCode;
userInfo.value.departmentName = department.departmentName;
}
</script>
执行结果: