网站首页 > 技术文章 正文
前言
async/await是非常强大的语法糖,是处理异步问题的一种简洁、高效的方式。虽然它并非“最终解决方案”,但与Promise配合使用,确实能极大地简化异步编程的复杂性。
从字面上理解,async 表示一个函数是异步的,await 则用来等待一个异步操作完成。二者结合使用,使得代码看起来更加同步化,从而提高了可读性和维护性。
MDN文档
- MDN: async/await
优点
- 提高代码可读性 使用async/await,代码写起来类似于同步代码,从而避免了then链式调用中常见的回调地狱。
async function() {
const data1 = await getApiData(1);
const data2 = await getApiData(2);
const data3 = await getApiData(3);
}
2.支持条件判断与流程控制可以直接在if条件语句中使用await,使得复杂逻辑更加简洁。
if(await getApiData(true)){
// ...
}
3.提高复杂流程的清晰度 使用async/await重构复杂的Promise链,代码会变得更加清晰易懂。
原始Promise写法:
let arr = [];
new Promise((resolve) => {
if (arr.length) {
resolve();
} else {
getApiData().then((res) => {
if (res.data.length) {
arr = res.data;
resolve();
} else {
console.log('数据为空')
}
})
}
}).then(() => {
arr.forEach(() => {});
})
重构为async/await写法:
let arr = [];
async function fn() {
if (!arr.length) {
const res = await getApiData();
if (res.data.length) {
arr = res.data;
} else {
console.log('数据为空')
return;
}
}
arr.forEach(() => {})
}
fn();
缺点
- 错误处理麻烦 异常需要使用try...catch进行捕获,如果请求接口出现错误,错误信息就需要在catch中处理。如果错误信息没有明确的区分,可能会影响代码的可维护性。
- 不能并行执行多个异步操作await会阻塞后续代码的执行,直到当前Promise完成。如果需要并行执行多个异步操作,需要额外的处理。
- 全局错误捕获问题 异步函数中的全局错误需要通过window.onerror来捕获,但window.onerror会捕获一些不相关的错误,增加了系统开销。unhandledrejection事件可以用于捕获Promise中的未处理异常。
- 局部错误捕获问题try...catch语句内部的变量,无法被外部catch捕获,导致错误捕获范围有限。
- 不支持部分Promise方法async/await不支持像Promise.race()、Promise.all()等原生Promise方法,因此如果你需要这些方法,建议直接使用Promise。
- 调试问题 在调试过程中,异步代码的行为可能不如预期,尤其在嵌套较深的async/await时,可能需要多次调试才能找到问题所在。
使用技巧
技巧1: 全局作用域下使用async/await
async函数只能在异步环境中调用,在全局作用域下不能直接使用async。你可以使用自执行匿名函数(IIFE)来解决这个问题:
(async () => {
const data = await function();
})();
在React中使用
React的useEffect中不能直接使用async函数,因为它返回的是一个Promise,React期望useEffect返回一个清理函数。正确的做法是将async函数封装在一个内部函数中并执行:
useEffect(() => {
async function fetchData() {
const response = await MyAPI.getData(someId);
// 处理数据
}
fetchData();
}, [someId]); // 或者[],如果依赖为空
技巧2: 在类方法中使用async/await
你可以在类方法中使用async/await来处理异步操作:
class Animal {
async getAnimalInfo() {
const res = await fetch('https://api.example.com/');
return await res.json();
}
}
const animal = new Animal();
(async () => {
const data = await animal.getAnimalInfo();
})();
技巧3: 使用Promise.all来并行处理多个await
当你需要并行执行多个异步操作时,可以使用Promise.all()来同时发起多个异步请求:
const func = async () => {
// 使用Promise.all来并行处理多个异步请求
const [data1, data2] = await Promise.all([
getData(1),
getData(2)
]);
}
技巧4: 串行与并行的结合使用
你可以根据需求选择是否让异步操作串行或并行执行。
const func = async () => {
// 串行
const data1 = await getApiData(1);
const data2 = await getApiData(2);
// 并行
const data3Promise = getApiData(3);
const data4Promise = getApiData(4);
const data5 = await data3Promise;
const data6 = await data4Promise;
}
技巧5: 在循环中使用await
forEach中无法直接使用async/await,因此需要使用for...of循环或map与Promise.all来处理。
串行:
const func = async () => {
const names = ['a', 'b'];
for (const name of names) {
const data = await getApiData(name);
}
}
并行:
const func = async () => {
const names = ['a', 'b'];
const promises = names.map(x => getApiData(x));
for (const name of promises) {
const data = await name; // 等待Promise执行完成
}
}
技巧6:使用async/await优化递归
递归函数是编程中的一种常用技术,async/await可以很容易地使递归函数进行异步操作。
/ 异步递归函数
async function func(nodes) {
for (const node of nodes) {
await asyncProcess(node);
if (node.children) {
await func(node.children);
}
}
}
// 示例
async function asyncProcess(node) {
// 对节点进行异步处理逻辑
}
技巧7:结合async/await和事件循环
使用async/await可以更好地控制事件循环,像处理DOM事件或定时器等场合。
// 异步定时器函数
async function funcTimeout(fn, ms) {
await new Promise(resolve => setTimeout(resolve, ms));
fn();
}
// 示例
funcTimeout(() => console.log('Timeout after 2 seconds'), 2000);
总结
虽然async/await有一些缺点,比如无法直接处理Promise的race、all等原生方法,或者调试时的不便,但它仍然是现代JavaScript中非常强大的工具。通过合理的使用技巧,可以极大地提升代码的可读性与可维护性。
如果要处理更复杂的异步流,async/await结合Promise仍然是最推荐的方案。对于一些极其复杂的异步操作流,RxJS等工具是一个备选,但由于学习和维护成本较高,通常不推荐在简单项目中使用。
- 上一篇: 网站性能不佳?试试这十大前端性能优化技巧!
- 下一篇: 学好Web前端开发,需要掌握什么方法与技巧?
猜你喜欢
- 2025-01-10 2023年最火的300个JS会议/演讲清单(国外)
- 2025-01-10 PS通道抠图技巧:如何快速抠出风景中的大树?
- 2025-01-10 互联网大佬发布《UI组件库二次封装技巧》,在GitHub引起热议
- 2025-01-10 倒车时,新手司机如何判断,车身与车位前端垂直距离大于1.5米?
- 2025-01-10 aardio + AI 大模型自动编写 Python 代码、网页前端代码的经验与技巧
- 2025-01-10 前端开发中,对图片的优化技巧有哪些?
- 2025-01-10 小技巧,如何使用 webpack 降低前端资源文件维护成本
- 2025-01-10 前端开发者都应知道的 jQuery 小技巧
- 2025-01-10 PICC置管时为防导管异位,我们这样做
- 2025-01-10 「电商设计」C4D产品建模,新手必看小技巧
你 发表评论:
欢迎- 493℃几个Oracle空值处理函数 oracle处理null值的函数
- 488℃Oracle分析函数之Lag和Lead()使用
- 486℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 473℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 467℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 462℃【数据统计分析】详解Oracle分组函数之CUBE
- 445℃Oracle有哪些常见的函数? oracle中常用的函数
- 439℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 最近发表
-
- Spring Boot跨域难题终结者:3种方案,从此告别CORS噩梦!
- 京东大佬问我,SpringBoot为什么会出现跨域问题?如何解决?
- 在 Spring Boot3 中轻松解决接口跨域访问问题
- 最常见五种跨域解决方案(常见跨域及其解决方案)
- Java Web开发中优雅应对跨域问题(java跨域问题解决办法)
- Spring Boot解决跨域最全指南:从入门到放弃?不,到根治!
- Spring Boot跨域问题终极解决方案:3种方案彻底告别CORS错误
- Spring Cloud 轻松解决跨域,别再乱用了
- Github 太狠了,居然把 "master" 干掉了
- IntelliJ IDEA 调试 Java 8,实在太香了
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)