当前位置: 首页 > news >正文

JavaScript 异步编程终极语法(async/await )

JavaScript 异步编程终极语法:async/await 完全指南,基于 Promise,用同步写法写异步代码,是目前前端 / Node.js 主流标准。


一、async/await 是什么?

async/await 是ES2017 引入的语法糖底层 100% 基于 Promise。它让异步代码写法和阅读都像同步代码,但底层依然是非阻塞的。

据 2023 State of JS 调查,超过90% 开发者在使用 async/await。

// 像同步一样优雅的异步代码 async function getUserData(userId) { const response = await fetch(`/api/users/${userId}`) const user = await response.json() return user }

二、本文你将学到

  • async/await 本质(就是 Promise)
  • async 关键字:把函数变成返回 Promise 的函数
  • await:暂停执行但不阻塞主线程
  • try/catch 做异步错误处理(最舒服的方式)
  • 串行 vs 并行执行(性能关键)
  • 最常见 5 个坑与避坑
  • async/await 与事件循环、微任务的关系

前置知识:Promise、事件循环


三、三种异步写法对比

1. 回调(老办法,嵌套地狱)

function getUserPosts(userId, callback) { fetchUser(userId, (err, user) => { if (err) return callback(err) fetchPosts(user.id, (err, posts) => { if (err) return callback(err) fetchComments(posts[0].id, (err, comments) => { callback(null, { user, posts, comments }) }) }) }) }

2. Promise 链式(好一点,但仍有嵌套)

function getUserPosts(userId) { return fetchUser(userId) .then(user => fetchPosts(user.id) .then(posts => fetchComments(posts[0].id) .then(comments => ({ user, posts, comments })) ) ) }

3. async/await(现代最清晰)

async function getUserPosts(userId) { const user = await fetchUser(userId) const posts = await fetchPosts(user.id) const comments = await fetchComments(posts[0].id) return { user, posts, comments } }

四、餐厅类比(秒懂)

  • 不用 async/await:站在柜台等餐,阻塞后面的人
  • 用 async/await:坐下点单,厨房做菜(异步),你可以玩手机(不阻塞)
  • 做好了服务员端来(Promise 决议),你继续吃(函数恢复执行)

核心:await 看起来在等,实际上 JS 主线程完全空闲。


五、async 关键字

作用只有一个:让函数返回 Promise

// 普通函数 function greet() { return 'Hello' } greet() // "Hello" // async 函数 async function greetAsync() { return 'Hello' } greetAsync() // Promise { <fulfilled>: "Hello" }

规则

  1. return 普通值 → 自动包装Promise.resolve(值)
  2. throw 错误 → 自动变成Promise.reject(错误)
  3. return Promise → 不会重复包装

支持所有函数形式

  • 普通函数
  • 函数表达式
  • 箭头函数
  • 对象方法
  • 类方法

六、await 关键字

作用:暂停 async 函数,直到 Promise 落定,然后返回结果

只能在两个地方用 await

  1. async 函数内部
  2. ES 模块顶层(top-level await)

可以 await 什么?

  • 任何 Promise(最常用)
  • thenable 对象
  • 普通值(会立刻继续,但仍进入微任务)

关键特性:await 暂停函数,不暂停线程

async function test() { console.log(1) await delay(1000) console.log(2) } console.log('A') test() console.log('B') // 输出顺序:A → 1 → B → 2

底层原理

await 会把后面的代码变成微任务,等 Promise 决议后再执行。等价于:

async example() → 等价于 → example().then(...)

七、错误处理:try/catch/finally

async/await 最爽的地方:用同步的 try/catch 处理异步错误

async function fetchUserData(userId) { try { const res = await fetch(`/api/users/${userId}`) if (!res.ok) throw new Error('HTTP 错误') return await res.json() } catch (err) { console.error('失败:', err.message) throw err // 继续向上抛 } finally { // 无论成功失败都执行 hideLoading() } }

常见陷阱

catch 后不 rethrow → 错误被 “吃掉”,函数返回 undefined。


八、串行 vs 并行(性能分水岭)

1. 串行(慢)

每个请求等上一个完成。

// 总耗时 ≈ 三个请求时间相加 const user = await fetchUser(userId) const posts = await fetchPosts(userId) const notes = await fetchNotes(userId)

2. 并行(快,推荐)

所有请求同时发送,用Promise.all

// 总耗时 ≈ 最慢那个请求 const [user, posts, notes] = await Promise.all([ fetchUser(userId), fetchPosts(userId), fetchNotes(userId) ])

选择规则

  • 串行:下一步依赖上一步结果
  • 并行:互相独立,追求速度

九、Promise 组合方法(和 await 天生一对)

  • Promise.all:全部成功才成功,任一失败立即失败
  • Promise.allSettled:全部完成,不管成败
  • Promise.race:谁先完成谁赢(成功失败都算)
  • Promise.any:谁先成功谁赢
  • Promise.withResolvers:外部控制 resolve/reject
  • Promise.try:统一捕获同步 / 异步错误

十、最常见 5 个错误(必考)

1. 忘记写 await

拿到 Promise 对象,不是结果。

const res = fetch('/api') // ❌ 是 Promise const data = await res.json() // ❌ 崩溃

2. forEach + await 无效

forEach 不会等待异步函数。✅ 替换为for...ofPromise.all

3. 无脑串行,本该并行

慢 2~10 倍。

4. 没有错误处理

未捕获的 Promise 拒绝会崩溃应用。

5. try 里 return 但没 await

错误抓不到!

// ❌ 错 try { return fetch(...) } catch {}
// ✅ 对 try { return await fetch(...) } catch {}

十一、Top-level await(ES 模块)

在模块最外层直接使用 await,无需 async 函数。

// config.js const config = await fetch('/config.json').then(r => r.json()) export default config

适用场景:

  • 加载配置
  • 动态导入
  • 数据库连接初始化
  • 特性检测

十二、高级模式

1. 指数退避重试

async function fetchWithRetry(url, retries = 3) { for (let i = 0; i < retries; i++) { try { return await fetch(url) } catch (e) { if (i === retries - 1) throw e await delay(1000 * 2 ** i) } } }

2. 超时控制

async function withTimeout(promise, ms) { return Promise.race([ promise, new Promise((_, reject) => setTimeout(() => reject(new Error('超时')), ms) ) ]) }

3. 取消请求(AbortController)

4. 异步迭代器 for await...of


十三、核心总结

  • async/await =Promise 的语法糖
  • async 函数一定返回 Promise
  • await暂停函数,不阻塞线程
  • await 后面的代码是微任务
  • 错误处理用try/catch
  • 并行用Promise.all,性能提升巨大
  • 是目前工业界标准异步写法

📦 概念 汇总

1. 核心概念

  • async/await同类:Promise 语法糖、协程、线性异步、generator + yield
  • async function同类:Promise 包装函数、异步函数、隐式返回 Promise
  • await同类:暂停执行、等待 Promise、微任务调度

2. 执行与调度

  • 微任务(Microtask)同类:Promise 回调、await 后续代码、优先级高于宏任务
  • 非阻塞暂停同类:协程、挂起、异步让出线程
  • Top-level await同类:模块异步初始化、动态导入、配置等待

3. 错误处理

  • async try/catch同类:同步风格错误捕获、Promise.catch ()、错误冒泡
  • 错误被吃掉同类:未 rethrow、隐式 resolve、隐形 BUG

4. 并发模式

  • 串行异步同类:依赖执行、顺序请求、瀑布式请求
  • 并行异步同类:并发请求、Promise.all、同时执行
  • 指数退避重试同类:容错、重试机制、抖动避免
  • 超时控制同类:Promise.race、熔断、请求保护

5. 相关 API

  • Promise.all同类:并行等待、全部成功
  • Promise.allSettled同类:容忍失败、批量结果
  • Promise.race同类:竞速、优先返回
  • Promise.any同类:优先成功、多源备用
  • AbortController同类:异步取消、终止请求、清理机制
  • Async Iterator同类:异步流、for await...of、流式读取

6. 反模式 / 陷阱

  • Missing await同类:Promise 对象误用、undefined 崩溃、类型错误
  • forEach + async同类:并发失控、不等待、执行顺序混乱
  • Return without await in try同类:错误逃逸、catch 不生效、隐性 bug
  • Unhandled Rejection同类:未捕获异常、程序崩溃、控制台警告
http://www.jsqmd.com/news/830413/

相关文章:

  • 物业临时工排班管理的技术破局:栎偲考勤神器的AI与离线方案详解
  • 告别DLL缺失困扰:Visual C++运行库一站式解决方案
  • Doramagic开源工具箱:开发者效率提升的模块化实践
  • 冰狐冷冻油 | 18年专注制冷压缩机冷冻油源头工厂/代工贴牌/OEM/ODM - 新闻快传
  • 如何使用ubuntu搭建一个无盘PC启动服务器
  • 【Appium 系列】第11节-Toast+弹窗处理 — 移动端最让人头疼的几种弹窗
  • 主流原型设计工具介绍
  • AI开发者如何快速接入多模型服务,五分钟搞定Python调用示例
  • macOS外接显示器控制终极指南:轻松掌控亮度与音量的完整方案
  • 别再只会用DC-DC了!手把手教你用SPX3819这类LDO芯片,搞定5V转3.3V的电路设计(附外围电路图)
  • 2026最权威的六大AI辅助论文神器推荐榜单
  • 深度解析:如何通过MonitorControl实现macOS外接显示器硬件级控制
  • 冰狐冷冻油替换开利/汉钟/约克/比泽尔/麦克维尔/复盛/顿汉布什/特灵/莱富康/克莱门特/神钢/丹佛斯/日立/冰轮/冰山制冷压缩机冷冻油平替型号全表 - 新闻快传
  • C++、汇编与易语言:三大编程语言深度对比
  • 【Appium 系列】第12节-智能路由 — API测试 vs UI 测试的自动选择
  • 模型逆向攻击(MIA)实战剖析:从原理到攻防演进
  • 忘记压缩包密码怎么办?3步找回加密文件的完整免费解决方案
  • KUKA机器人FSoE安全地址丢了别慌!手把手教你用WorkVisual手动找回(附KRC4标准柜地址表)
  • 如何选择适合你的双向拉绳开关?2026最新评测与选购指南 - 新闻快传
  • 从LED点阵到动态动画:基于ESP32的万圣节创意显示项目实战
  • wxhelper终极实战:深度揭秘微信逆向工程完整解决方案
  • 微信小程序wx.navigateTo传参实战:从基础到动态数据绑定
  • QLC SSD可靠性提升:LDPC软判决与智能固件如何实现低开销加固
  • Arm Neoverse CMN-650一致性网格网络架构与配置解析
  • Halbot框架解析:从零构建可扩展聊天机器人的实践指南
  • Doramagic工具箱:模块化脚本集的设计哲学与工程实践
  • 使用Nodejs开发后端服务如何集成Taotoken调用多模型API
  • 导师不会告诉你的6款AI论文工具:巨鲸写作可一键引真实文献 - 麟书学长
  • AI智能体安全防护框架AgentGuard:构建纵深防御策略链
  • YOLOv5/v7改进系列——融合EfficientNetV2主干网络的轻量化部署实践