JavaScript 异步编程指南:从回调到 async/await
JavaScript 的异步模型是前端开发的核心能力之一。本文从事件循环出发,梳理 callback、Promise 到 async/await 的演进路线。
1. 为什么 JavaScript 需要异步
JavaScript 是单线程语言,这意味着同一时间只能执行一段代码。如果耗时操作阻塞主线程,页面就会卡顿甚至失去响应。因此,网络请求、定时器、文件读写等操作必须被设计成异步执行。
2. 回调函数时代
最早的异步写法是回调函数:
1 | setTimeout(() => { |
嵌套一多,就会出现「回调地狱」(Callback Hell),代码横向扩展,难以维护:
1 | getData(url, (data) => { |
3. Promise:链式调用的优雅
ES6 引入的 Promise 将异步操作封装为对象,通过 .then() 和 .catch() 进行链式处理:
1 | fetch('/api/user') |
Promise 解决了回调地狱的问题,但在复杂场景下,链式调用依然会显得冗长。
4. async/await:写异步像写同步
ES2017 推出的 async/await 是 Promise 的语法糖,让异步代码的可读性大幅提升:
1 | async function getUser() { |
常见误区
await只能在async函数内部使用(顶层 await 在 ES2022 的模块中已支持)。async函数默认返回一个 Promise,即使你没有显式 return。- 多个无依赖的异步请求不要顺序
await,应该用Promise.all并行执行:
1 | const [users, posts] = await Promise.all([ |
5. 事件循环:理解执行顺序
浏览器中,JavaScript 引擎通过调用栈(Call Stack)执行同步代码,异步任务则被放入任务队列(Task Queue)。事件循环(Event Loop)的职责就是:
- 先清空调用栈中的同步代码。
- 检查微任务队列(Microtask Queue,如 Promise.then),全部执行完毕。
- 取出一个宏任务(Macrotask,如 setTimeout、setInterval)执行。
- 重复步骤 2~3。
理解这一机制,才能正确处理复杂的异步执行顺序问题。
总结
从回调到 Promise,再到 async/await,JavaScript 的异步编程变得越来越优雅。但在实际开发中,仍需掌握事件循环原理,才能避免踩入执行顺序和性能优化的坑。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 GALAXY!