
本文深入探讨了j*ascript中`await`关键字的正确使用方法,解决了在异步函数中因未正确标记`async`和返回promise而导致的执行顺序不一致问题。通过详细的代码示例和解释,揭示了`await`仅在等待promise时才暂停执行的原理,并提供了两种关键的解决方案:将函数标记为`async`,以及确保函数返回一个promise,从而实现预期的同步化异步操作。
在现代J*aScript开发中,async/await语法极大地简化了异步代码的编写和阅读。然而,如果不完全理解其背后的机制,有时会导致出乎意料的执行顺序。本文将通过一个具体的案例,详细解析await的工作原理,并提供确保代码按预期执行的正确实践。
考虑以下J*aScript代码片段,它尝试使用await来控制异步操作的执行顺序:
console.log("1");
await reloadScenarios();
console.log("2");
const reloadScenarios = () => {
if (token) {
getScenario()
.then(({ scenarios }) => {
console.log("3");
const transformedScenarios = scenarios.map(option => ({
scenario: option.name,
description: option.categories.name,
value: option._id
}));
setOptions(transformedScformedScenarios);
// setSelectedOption(transformedScenarios[0]?.value || null);
})
.catch((error) => {
console.error('Failed to fetch scenario options:', error);
});
}
};开发者期望的执行顺序是 1 -> 3 -> 2,即在 reloadScenarios 完成其内部的异步操作(打印 3)之后,再继续执行 console.log("2")。然而,实际的执行顺序却是 1 -> 2 -> 3。这表明 await reloadScenarios() 并没有如预期那样暂停代码的执行。
await关键字只能在 async 函数内部使用,并且它的作用是暂停 async 函数的执行,直到它等待的 Promise 对象解决(resolved)或拒绝(rejected)。如果 await 后面的表达式不是一个 Promise,J*aScript 会将其立即解析为一个已解决的Promise,并继续执行。
在上述问题代码中,reloadScenarios 函数本身是一个普通的同步函数,它没有被标记为 async,并且它也没有直接返回一个 Promise。尽管 reloadScenarios 内部调用了 getScenario().then(...) 这样的异步操作,但 reloadScenarios 函数在启动这些异步操作后会立即返回 undefined(因为没有显式的 return 语句)。
因此,当执行到 await reloadScenarios() 时,reloadScenarios() 立即执行并返回 undefined。await 关键字看到一个非 Promise 值 (undefined),会将其视为一个已解决的Promise,并立即允许外部的 async 函数(假设这段代码在一个 async 函数中)继续执行 console.log("2")。之后,getScenario().then(...) 中的异步回调才会在事件循环中被执行,最终打印 3。
要实现期望的执行顺序 1 -> 3 -> 2,我们需要确保 await reloadScenarios() 确实在等待一个Promise,并且这个Promise会在 reloadScenarios 内部的所有异步操作完成后才解决。这可以通过两种主要方式实现:
最直接的方法是将 reloadScenarios 函数标记为 async。一个 async 函数总是会返回一个 Promise。如果 async 函数内部没有显式地返回一个 Promise,它会隐式地返回一个已解决的Promise,其值是函数内部的返回值(如果没有显式返回值,则为 undefined)。
console.log("1");
await reloadScenarios(); // 假设这段代码在一个 async 函数中
console.log("2");
const reloadScenarios = async () => { // 标记为 async
if (token) {
getScenario()
.then(({ scenarios }) => {
console.log("3");
const transformedScenarios = scenarios.map(option => ({
scenario: option.name,
description: option.categories.name,
value: option._id
}));
setOptions(transformedScenarios);
})
.catch((error) => {
console.error('Failed to fetch scenario options:', error);
});
}
};然而,仅仅标记为 async 仍然不足以解决问题! 尽管 reloadScenarios 现在返回一个Promise,但这个Promise会在 getScenario() 启动后立即解决,而不是在 getScenario().then(...) 中的回调执行后解决。因为 getScenario().then(...) 本身是一个异步操作,它不会阻塞 async 函数的同步部分执行。
为了让 async 函数的 Promise 在内部异步操作完成后才解决,我们需要采取第二个关键步骤。
白瓜面试
白瓜面试 - AI面试助手,辅助笔试面试神器
162
查看详情
为了让 async reloadScenarios 函数的 Promise 在 getScenario() 的 Promise 解决后才解决,我们需要在 reloadScenarios 函数内部显式地 return getScenario() 返回的 Promise。
完整且正确的实现:
// 假设这段代码在一个 async 函数中,例如:
async function main() {
console.log("1");
await reloadScenarios();
console.log("2");
}
const reloadScenarios = async () => { // 标记为 async
if (token) {
// 关键:返回 getScenario() 返回的 Promise
return getScenario()
.then(({ scenarios }) => {
console.log("3");
const transformedScenarios = scenarios.map(option => ({
scenario: option.name,
description: option.categories.name,
value: option._id
}));
setOptions(transformedScenarios);
})
.catch((error) => {
console.error('Failed to fetch scenario options:', error);
// 确保错误也被传递,或者根据需要处理
throw error; // 重新抛出错误,让外部的 await 能够捕获
});
}
// 如果 token 不存在,也需要返回一个 Promise,例如一个已解决的 Promise
return Promise.resolve();
};
// 调用主函数
// main(); 在这个修正后的版本中:
现在,执行顺序将是期望的 1 -> 3 -> 2。
替代方案:在 async 函数内部使用 await
另一种更符合 async/await 风格的写法是,在 async 函数 reloadScenarios 内部也使用 await 来等待 getScenario() 的结果:
async function main() {
console.log("1");
await reloadScenarios();
console.log("2");
}
const reloadScenarios = async () => {
if (token) {
try {
// 在 async 函数内部使用 await
const { scenarios } = await getScenario();
console.log("3");
const transformedScenarios = scenarios.map(option => ({
scenario: option.name,
description: option.categories.name,
value: option._id
}));
setOptions(transformedScenarios);
} catch (error) {
console.error('Failed to fetch scenario options:', error);
throw error; // 重新抛出错误,让外部的 await 能够捕获
}
}
// 如果 token 不存在,async 函数会隐式返回一个已解决的 Promise
};
// main();这种写法更为简洁和直观,它同样确保了 async reloadScenarios 函数返回的Promise会在 await getScenario() 完成后才解决。
要正确地使用 await 关键字并确保异步操作的执行顺序符合预期,请遵循以下关键原则:
通过理解和应用这些原则,您可以有效地控制J*aScript中的异步流程,编写出更健壮、更易读的异步代码。
以上就是深入理解J*aScript中await的执行机制与正确使用姿势的详细内容,更多请关注其它相关文章!
# 回调
# 荆门seo网站优化
# 沈阳企业网站优化优势
# seo怎么制作广告
# 安溪谷歌seo公司电话
# 高安网站关键词优化
# 黄冈本地seo推广
# 品牌网站怎么推广
# 推广营销流程及方案
# 天津靠谱营销推广企业
# seo二八框架户
# 返回值
# 两种
# javascript
# 抛出
# 在等待
# 它会
# 是一个
# 这段
# 会在
# 后才
# javascript开发
# ios
# ai
# go
# java
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
优化推广96088 】
【
技术知识133117 】
【
IDC资讯59369 】
【
网络运营7196 】
【
IT资讯61894 】
相关推荐:
狙击外星人小游戏在线链接_狙击外星人小游戏网页链接
哔哩哔哩的|直播|间怎么送礼物_哔哩哔哩|直播|送礼操作指南
t3出行如何使用微信支付
AO3中文版手机快速通道_AO3最新稳定链接更新
掌握Go App Engine项目结构与GOPATH:包管理与导入实践
126邮箱网页在线登录2025_126邮箱网页版入口官方地址
Final Cut Pro视频加EQ教程
三角洲行动2025年9月10日摩斯密码分享
sublime如何处理超大文件不卡顿 _sublime打开大日志文件技巧
QQ邮箱注册地址 免费获取QQ邮箱账号
抖音赚钱快速入门_新手必看的抖音赚钱步骤
三星A55应用闪退排查步骤_Samsung A55稳定性优化技巧
高效调试PHP大型嵌套数组:JSON序列化与可视化工具实践
微博网页版访问入口 微博网页版网页端使用指南
edge浏览器怎么修改语言为中文_Edge界面语言切换教程
excel怎么制作考勤表 excel考勤模板与函数公式讲解
《微信》视频号原创声明开启方法
百度浏览器无法安装扩展程序_百度浏览器插件安装失败原因解析
谷歌邮箱官方入口链接 谷歌邮箱网页版电脑端快速登录
Excel如何快速合并单元格内容_Excel文本合并与函数操作技巧
Python定时发送QQ消息
解决CSS background 属性中 cover 关键字的常见误用
小红书如何引流到私信?引流到私信有用吗?
Word如何将文字快速转成表格 Word文本转换成表格功能使用技巧【效率】
使用document.execCommand实现Web文本编辑器加粗/取消加粗
yy漫画登录页面官方入口_yy漫画在线阅读网址入口
感染了幽门螺杆菌一定会导致胃癌吗?蚂蚁庄园今日答案最新11.30
PHP安全加载非公开目录图片与动态内容类型处理指南
MySQL多重关联查询:利用别名高效获取同一表的多个关联字段
韩小圈网页版PC端入口 韩小圈网页版官方网站入口
阿里云共享相册入口在哪
漫蛙manwa2网页版书签同步链接_漫蛙manwa多设备登录入口
如何在解析前预检查XML文件的完整性? 比如检查文件大小或特定结束标签
PDF文件去水印平台入口 PDF水印删除网址
Go语言中方法与接收器:指针和值类型的调用机制详解
Cassandra中复合主键、二级索引与ORDER BY排序的限制与解决方案
精通VS Code多光标编辑以实现闪电般快速的修改
猫眼app抢票快还是小程序快
使用TinyButStrong生成HTML并结合Dompdf创建PDF教程
微信注销后银行卡解绑了吗_微信注销后银行卡解绑状态
如何用mysql开发用户注册登录功能_mysql用户注册登录数据库设计
植物大战僵尸95版游戏版下载_植物大战僵尸95版游戏版安装指南
电脑“无法访问指定设备、路径或文件”怎么办?五种权限设置方法
天天漫画2025最新入口 天天漫画永久有效登录入口
Excel如何制作月度销售统计图_Excel动态图表制作与控件应用
CSS布局中意外顶部空白的调试与解决:深入理解padding-top
在J*a里什么是行为抽象_抽象行为对代码复用的提升作用
铁路12306买票怎么选双人铺 铁路12306卧铺分配规则说明
《全民k歌》音乐怎么下载到本地2025
Sublime怎么配置YAML文件格式化_Sublime YAML Formatter插件教程
2025-11-28
运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。