【每日一面】async/await 的原理

news/2025/10/28 17:26:22/文章来源:https://www.cnblogs.com/keepsmart/p/19172342

基础问答

问:async/await 的原理是什么?

答:关键字本身就是 Promise 的语法糖,依托于生成器函数 (Generator) 函数能力实现的。async 关键字标志这个函数为异步函数,并且将返回结果封装为一个 Promise,await 则是暂停当前执行,等待后续的异步操作完成后再恢复,相当于 Generator 的 yield 。只是在 Generator 中,需要手动调用 next() 触发执行, async 函数则内置该操作,自动根据 await 的异步结果执行后续函数步骤。

扩展延伸

在上面,提到了一个生成器函数(Generator),这个是 JavaScript 中的一种特殊函数,可以暂停和恢复函数执行。在平时的开发中,基本很少见到这个函数的使用,不过面试的时候,只要聊到了 async/await 内容,90% 以上的概率会问到生成器函数。

生成器函数使用 function* 语法定义,他会返回一个生成器对象,而不是和普通函数一样返回指定的结果,如下示例:

// 定义一个Generator函数,包含2个暂停点(yield)和1个返回值(return)
function* syncGenerator() {console.log('1. 函数开始执行');yield '第一个暂停结果'; // 第一个暂停点,返回值为'第一个暂停结果'console.log('2. 函数恢复执行');yield '第二个暂停结果'; // 第二个暂停点,返回值为'第二个暂停结果'console.log('3. 函数即将结束');return '最终返回结果'; // 函数执行完毕,返回最终结果
}// 1. 调用Generator函数,返回迭代器(此时函数体未执行)
const genIterator = syncGenerator();
console.log('调用Generator后,函数未执行:', genIterator); // 输出:Generator {<suspended>}// 2. 第一次调用next():执行到第一个yield,暂停
const result1 = genIterator.next();
console.log('第一次next()结果:', result1); 
// 输出顺序:
// 1. 函数开始执行
// 第一次next()结果:{ value: '第一个暂停结果', done: false }(done=false表示未执行完毕)// 3. 第二次调用next():从第一个yield恢复,执行到第二个yield,暂停
const result2 = genIterator.next();
console.log('第二次next()结果:', result2);
// 输出顺序:
// 2. 函数恢复执行
// 第二次next()结果:{ value: '第二个暂停结果', done: false }// 4. 第三次调用next():从第二个yield恢复,执行到return,结束
const result3 = genIterator.next();
console.log('第三次next()结果:', result3);
// 输出顺序:
// 3. 函数即将结束
// 第三次next()结果:{ value: '最终返回结果', done: true }(done=true表示执行完毕)// 5. 第四次调用next():函数已结束,后续调用均返回{ value: undefined, done: true }
const result4 = genIterator.next();
console.log('第四次next()结果:', result4); // 输出:{ value: undefined, done: true }

核心执行规则:

  1. 首次调用 Generator 函数:仅返回迭代器,函数体不执行;
  2. 每次调用 next ():函数从上次暂停位置继续执行,直到遇到下一个yield或return;
  3. 返回结果结构:next()返回的对象包含value(yield后的值或return的值)和done(布尔值,标识是否执行完毕);
  4. 执行完毕后:后续调用next(),done始终为true,value为undefined。

面试之外,你应该知道,Generator 函数的核心价值在于“异步流程控制”,即,通过yield暂停执行异步操作,等待异步结果返回后, 调用 next() 恢复执行。这就是 async/await 的底层逻辑雏形。

// 模拟接口请求(异步函数,返回Promise)
function fetchUser() {return new Promise((resolve) => {setTimeout(() => {resolve({ id: 1, name: '前端面试' });}, 1000);});
}function fetchOrders(userId) {return new Promise((resolve) => {setTimeout(() => {resolve([{ orderId: '1001', goods: '面试指南' }]);}, 1000);});
}// 定义异步Generator函数:用yield暂停异步操作
function* asyncGenerator() {console.log('开始请求用户信息');const user = yield fetchUser(); // 暂停,等待fetchUser的Promise完成console.log('用户信息请求完成:', user);console.log('开始请求订单信息');const orders = yield fetchOrders(user.id); // 暂停,等待fetchOrders的Promise完成console.log('订单信息请求完成:', orders);return { user, orders }; // 最终返回结果
}// 手动执行异步Generator函数(模拟async/await的自动执行器)
function runGenerator(genFn) {const genIterator = genFn(); // 获取迭代器// 定义递归执行函数function handleNext(result) {// 若Generator执行完毕,直接返回最终结果if (result.done) {return Promise.resolve(result.value);}// 若未执行完毕,处理yield返回的Promise(异步操作)// result.value是yield后的值(此处为fetchUser/fetchOrders返回的Promise)return Promise.resolve(result.value).then((res) => {// 异步操作完成后,调用next(res)恢复执行,将异步结果作为yield的返回值return handleNext(genIterator.next(res));}).catch((err) => {// 捕获异步错误,调用throw(err)将错误传入Generator函数return handleNext(genIterator.throw(err));});}// 启动第一次执行return handleNext(genIterator.next());
}// 执行异步Generator函数
runGenerator(asyncGenerator).then((finalResult) => {console.log('所有异步操作完成,最终结果:', finalResult);}).catch((err) => {console.log('异步操作出错:', err);});

async/await 本质是 Generator + 自动执行器的语法糖,二者核心逻辑可以一一对应上,只是 async/await 的封装大大简化了使用流程:

特性 Generator 函数 async/await
暂停 / 恢复标识 yield 关键字(手动标记暂停点) await关键字(自动标记暂停点)
执行控制 需手动调用迭代器的 next() 恢复执行 内置自动执行器,无需手动控制
异步结果处理 需手动用 Promise.resolve 等待异步结果 自动等待 await 后的 Promise 完成
错误处理 需手动调用 iterator.throw(err) 传入错误 用 try/catch 自动捕获错误
返回值 调用函数返回迭代器 调用函数返回 Promise
语法简洁度 较繁琐,需手动实现执行器 简洁,无需关注执行细节

面试追问

  1. 生成器函数?是怎么实现 async/await 的?
    具体代码参考扩展延伸部分内容,要代码描述。

  2. async/await 基础使用方式,使用 Promise 不是更好?为什么要用 async/await 关键字。

    async function waitRequest() {const resp = await axios.request('https://hello.com')const data = resp.data;return data、
    }
    

    可以使用Promise,这个是根据使用场景来的,async/await 只是将异步调用链转换成了同步代码,阅读维护起来更方便。
    如封装一个等待延时,通常使用的就是 await + new Promise 来实现,只是多数情况下 Promise 伴随着的是比较长的调用链,带来阅读不便,此时转换成同步代码就清晰易读了。

  3. 如果 await 的表达式返回了 reject,需要捕获吗?要怎么捕获?
    需要捕获,否则会触发“Uncaught (in Promise) Error”,中断代码执行,这个类似于 throw error。需要使用 try...catch 捕获 await 表达式产生的错误及reject。

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

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

相关文章

gmssl2.5常用命令

参考链接:https://zhuanlan.zhihu.com/p/618494579SM3计算摘要:echo -n hello | gmssl dgst -sm3 SM3计算HMAC:echo -n hello | gmssl dgst -sm3 -hmac 11223344556677881122334455667788SM4对输入字符加密:echo h…

上海电磁阀厂家最新竞争力评估推荐:高温电磁阀/高压电磁阀/防爆电磁阀/真空电磁阀/聚焦服务能力与产品特色

随着工业自动化程度不断提高以及高端流体控制需求增长,用户在选择电磁阀制造企业时面临诸多考量——如何评估企业技术实力、如何匹配不同工况的产品选型、如何保障设备长期稳定运行,成为工业采购决策中的核心关注点。…

如何在iPhone和Android设备上恢复已删除的电话号码

丢失手机上的联系人,感觉就像自己的一部分被抹去了。朋友、家人,甚至必要服务的联系人——所有信息都可能瞬间消失,而且似乎无法恢复。对一些人来说,失去商业联系人更是一场噩梦,会给他们带来巨大的经济压力。 无…

云栖实录:重构可观测 - 打造大模型驱动的云监控 2.0 与 AIOps 新范式

云监控 2.0 历经一年半的演进,已经完成了 ARMS、容器监控(Prometheus)、企业云监控的大部分系统整合、存储迁移等工作,剩余的 SLS CloudLens、基础云监控等也在下半年逐步迁移规划中。作者:司徒放(姬风) 纵观技…

2025 年房屋安全鉴定检测,山东房屋安全鉴定,房屋安全鉴定质量鉴定机构最新推荐,聚焦资质、案例、服务的五家机构深度解读

引言 房屋安全鉴定是保障建筑使用安全的核心环节,尤其在山东这样建筑类型丰富、部分区域面临灾后重建与抗震加固需求的地区,选择正规机构至关重要。当前市场存在资质参差不齐、数据造假等问题,为破解选择难题,本次…

0289-KVS-读取目录中的文件

环境Time 2022-12-16 WSL-Ubuntu 22.04 Rust 1.65.0前言 说明 参考:https://github.com/pingcap/talent-plan 目标 在上一节的基础上,根据提供的目录,到目录中进行文件的读取。 Cargo.toml [package] edition = &qu…

0288-KVS-根据索引读取文件

环境Time 2022-12-13 WSL-Ubuntu 22.04 Rust 1.65.0前言 说明 参考:https://github.com/pingcap/talent-plan 目标 在上一节的基础上,根据提供的索引,到文件中读取命令和值。 Cargo.toml [package] edition = "…

2025年南京机械钻井工程服务权威推荐榜单:砖井工程/打桩工程/环保检测井工程源头公司精选

在城市建设与环保政策双轮驱动下,南京机械钻井工程服务市场正迎来新一轮发展机遇,其中环保检测井工程已成为增长新引擎。 在当今城市基础设施更新和环保政策深入推进的背景下,南京机械钻井工程服务行业依托区域经济…

如何在 Mac 上恢复已删除的文件:解决方案和预防技巧

在 Mac 上删除文件并不意味着一切就此结束。如今,macOS 用户有多种方法可以恢复已删除的数据。即使文件已从 Mac 的“垃圾箱”中删除,您仍然可以选择其他方法。您可以使用 macOS 的内置功能进行数据恢复,也可以使用…

GMT0009 SM2密钥算法使用规范

原文链接:https://blog.csdn.net/A_CAT_journey/article/details/1393903021、什么是国密密钥对加密 国密密钥对加密格式定义在《GMT 0009-2012 SM2密码算法使用规范》文档中,具体的规范格式如下:在SM2密钥对传递时…

2025精密/五金/冲压/塑料/模具配件/司筒/镶件/零件企业推荐榜:锦鸿深耕三十载筑服务网络,这些实力派值得关注​

在有着 “全球模具产业之都” 之称的东莞,模具配件作为 “工业之母” 的核心支撑,正随产业升级不断突破。2025 年市场需求持续向高精度、快响应倾斜,以下几家模具配件企业凭借技术积淀与服务能力脱颖而出。​ 东莞市…

2025发泡混凝土领域厂家推荐榜:云南锦乐建筑领衔,多企业助力绿色建材发展​ 随着

随着绿色建筑理念的普及,兼具轻质、保温、隔音与环保特性的发泡混凝土,在民用建筑、市政配套等领域的需求持续增长。为展现该领域优质企业实力,本次 2025 发泡混凝土领域推荐榜聚焦云南区域,结合企业业务专注度、技…

2025年泳池水循环设备厂家权威推荐榜单:泳池水净化设备 /钢结构泳池/泳池恒温设备源头厂家精选

随着全民健身战略的深入实施和人们对健康生活品质要求的提升,泳池水循环设备行业正迎来新一轮发展机遇。 据中国水处理行业协会统计数据显示,2024年中国泳池水处理设备市场规模已达86亿元人民币,预计到2027年将突破…

EasyExcel碰到问题记录

1、富文本中文字设置不同颜色和字体不生效String stringCellValue = cell.getStringCellValue();if (StringUtils.isNotBlank(stringCellValue) && stringCellValue.contains(startIndex) && stringCe…

2025年修护/二硫化硒去屑/香氛/控油蓬松/洗发水推荐榜:西安悦己容生物主打植萃护理,四大品牌以精准配方适配多元发质

随着消费者对发质护理的需求从 “基础清洁” 转向 “针对性修护”,植萃成分、无刺激配方、细分发质适配成为洗发水市场核心竞争点。基于成分安全性、使用体验与用户口碑,2025 年洗发水领域优质企业推荐如下:​ 西安…

2025喷涂/聚脲涂料领域源头厂家推荐榜:宁国创遂新材料领衔,多企业助力防腐防护升级​

在工业设备防腐、建筑防水、交通设施耐磨等场景中,聚脲涂料因具备快速固化、高弹性、耐候性强等优势,成为材料领域的重要选择。为展现聚脲涂料领域优质企业实力,本次 2025 推荐榜聚焦安徽区域,结合企业技术专业性、…

2025弯管领域源头厂家推荐榜:合肥市翼达机械领衔,多企业助力工业管件加工升级​

在汽车制造、暖通工程、家电生产等工业领域,弯管作为关键管件,其精度、材质适配性与加工效率直接影响下游产品性能。为展现弯管领域优质企业实力,本次 2025 弯管领域推荐榜聚焦安徽区域,结合企业技术专业性、产品适…

2025不锈钢剪板折弯推荐榜:上海一步一金属主打定制加工,四大企业以精准工艺赋能工业制造

随着机械制造、装饰工程等领域对不锈钢构件精度要求的提升,不锈钢剪板折弯作为关键加工环节,其工艺精度、定制化能力与交付效率成为企业竞争核心。基于加工质量、行业适配性与客户口碑,2025 年不锈钢剪板折弯领域优…

2025年碳氢肥料生产厂家权威推荐榜单:农产品用料/增产用肥/碳氢核肥邮沃源头厂家精选

在生态农业与绿色肥料需求日益增长的今天,碳氢肥料作为一种利用二氧化碳资源的新型肥料,正成为农资市场的热门选择。 随着国家“双碳”政策的深入推进和生态农业理念的普及,碳氢肥料市场近年来呈现出显著的增长态势…

算法分析--分治--3.矩阵乘法

1.1 题目描述 输入的第一行中有3个整数n, m,k,表示A矩阵是n行m列,B矩阵是m行k列。接下来的n行,每行m个数字,表示矩阵A中的元素。接下来的m行,每行k个元素,表示矩阵B中的元素。 【样例输入】 3 2 3 1 1 1 1 1 1 1 1…