本文档解释了 JavaScript 中的异步编程概念,涵盖了实现非阻塞代码执行的机制。它详细介绍了事件循环、消息队列、定时函数、Promise 以及 async/await 模式。有关闭包(常与异步代码一起使用)的相关信息,请参阅闭包,有关补充异步 JavaScript 的函数式编程技术的更多详细信息,请参阅高阶函数。
来源: README.md396-421 README.md1007-1056
JavaScript 本质上是单线程的,这意味着它一次只能执行一段代码。当操作需要很长时间才能完成时(例如网络请求或文件操作),这会带来挑战。异步编程通过允许执行继续而不等待这些长时间运行的操作完成来解决此问题。
来源: README.md396-421
事件循环是 JavaScript 处理异步操作的机制。它会持续检查调用栈是否为空,如果为空,则从消息队列中取出第一个回调函数,将其推入调用栈以供执行。
图表显示了 JavaScript 运行时环境的关键组成部分
来源: README.md396-421 README.md998-1006
| 队列类型 | 示例 | 优先级 | 行为 |
|---|---|---|---|
| 微任务 | Promise 回调(.then/.catch)、queueMicrotask()、process.nextTick() | 较高 | 所有微任务在下一个宏任务开始前完成 |
| 宏任务(任务) | setTimeout/setInterval 回调、I/O 操作、UI 渲染、事件回调 | 较低 | 每个事件循环迭代在处理完所有微任务后处理一个宏任务 |
来源: README.md396-421
JavaScript 提供内置函数来调度代码在延迟后或在特定时间间隔执行。
这些定时函数不保证精确计时——它们表示最短延迟,之后回调可能会执行,具体取决于调用栈的可用性。
来源: README.md422-446
这个特殊的定时函数会将回调函数的执行与浏览器的重绘周期同步,使其成为动画和视觉更新的理想选择。
与 setTimeout 不同,requestAnimationFrame
来源: README.md422-446
JavaScript 处理异步编程的方法随着时间的推移发生了显著变化,从回调到 Promise 再到 async/await 语法。
来源: README.md952-1006 README.md1007-1056
Promise 是表示异步操作最终完成或失败的对象。与回调相比,它们提供了更简洁的方式来处理异步代码。
Promise 可以处于三种状态之一
Promise 方法
Async/await 是在 Promise 之上构建的语法糖,它使异步代码看起来和行为更像同步代码,于 ES2017 引入。
Async/await 的关键方面
async 声明的函数会自动返回 Promiseawait 只能在 async 函数(或具有顶层 await 的模块)内部使用await 会暂停函数执行,直到 Promise resolveAsync/await 简化 Promise 链的示例
| Promise 链 | Async/Await 等效代码 |
|---|---|
fetchUser().then(user => { return fetchProfile(user); }).then(profile => { displayProfile(profile); }).catch(err => { handleError(err); }) | async function loadProfile() { try { const user = await fetchUser(); const profile = await fetchProfile(user); displayProfile(profile); } catch (err) { handleError(err); } } |
| 场景 | 推荐模式 | 原理 |
|---|---|---|
| 简单延迟 | setTimeout | 对基本计时需求简单明了 |
| 动画 | requestAnimationFrame | 针对与浏览器同步的视觉更新进行优化 |
| 顺序异步操作 | async/await | 线性操作中最具可读性的方法 |
| 并发操作 | Promise.all/Promise.allSettled | 高效处理多个并行任务 |
| 事件处理 | 回调(通过 addEventListener) | 事件驱动编程的标准 |
| 错误传播 | 带 try/catch 的 async/await | 最简洁的错误处理语法 |
阻塞事件循环:避免主线程上长时间运行的操作
回调地狱:深度嵌套的回调产生难以阅读的代码
未处理的 Promise 拒绝:遗漏的错误处理
内存泄漏:遗忘的计时器或事件监听器
竞态条件:异步操作时序不一致
来源: README.md952-1006 README.md1007-1056 README.md422-446
异步操作会带来开销和复杂性。请考虑这些性能方面
来源: README.md422-446 README.md396-421
异步 JavaScript 是创建响应式 Web 应用程序的基础。从回调到 Promise 再到 async/await 的演进,使得异步代码越来越易读和易于维护。理解事件循环、消息队列和各种异步模式,使开发人员能够为现代 JavaScript 应用程序编写高效的非阻塞代码。
本文档中涵盖的概念为使用 JavaScript 的异步功能奠定了基础。有关更高级的主题,请参阅有关Promise和async/await的相关 Wiki 页面。