请解释 async/await 在 JavaScript 中的执行机制,它是否会阻塞主线程或代码的执行?请结合事件循环说明其工作原理。
考察说明
考察对 async/await 底层原理和事件循环的理解,以及是否清楚其非阻塞特性。
回答思路
- 【回答框架 1】async/await 本身不阻塞代码执行。async 函数返回一个 Promise,await 表达式会暂停该 async 函数的执行,但不会阻塞主线程。当 await 等待的 Promise 尚未完成时,控制权会交还给事件循环,其他任务可以继续执行。
- 【回答框架 2】事件循环机制:JavaScript 主线程处理微任务和宏任务。await 相当于在 Promise 上挂载 then 回调,当 Promise 完成时,恢复 async 函数执行,该恢复过程作为微任务排队。因此,await 不会导致主线程阻塞,而是让出执行权,等待异步操作完成。
- 【回答框架 3】需要区分的是,如果在 async 函数内部有同步的耗时操作(例如大量计算),那么这部分代码会阻塞主线程,因为它是同步执行的。但 await 关键字本身不会造成阻塞,除非 await 等待的是一个同步执行的耗时操作(如为完成状态的 Promise 或立即解析的值)。
- 【回答框架 4】若要避免耗时操作阻塞,应使用异步 API(如 setTimeout、fetch、fs.readFile 等)来执行耗时任务,而不是使用同步版本。
- 【关键点 1】async/await 基于 Promise 和事件循环,不会阻塞主线程。
- 【关键点 2】await 会暂停当前 async 函数,但控制权交还给事件循环。
- 【关键点 3】同步耗时操作仍会阻塞主线程,await 本身并不保证操作非阻塞。
- 【关键点 4】恢复执行时通过微任务队列处理,不抢占其他任务执行。
- 【易错点 1】误解 await 会阻塞整个程序,实际上它只暂停当前 async 函数。
- 【易错点 2】将同步任务包装在 async 函数中不会使其变为异步,仍会阻塞。
- 【易错点 3】忽视 await 后代码的执行时机,可能依赖于微任务调度顺序。