JavaScript async/await:事件循环与执行顺序详解
这门课面向已经在写 JavaScript 的开发者:你会用 .then(),会写 async/await,也会调用 setTimeout,但代码的执行顺序在你眼里仍然像魔法。你把 A 写在 B 前面,B 却先打印;一个你最后才写的 .then(),不知怎么就抢在了更早写的 setTimeout(fn, 0) 前面;你说不清 await 到底对它下面那行代码做了什么。解法不是再学一遍语法,而是一套心智模型:一个调用栈、一个微任务队列、一个任务队列,外加一个决定谁下一个运行的事件循环。一旦你能看见这三个地方,执行顺序就不再是魔法,而是可以在纸上推算出来的东西。
课程结束后,你将能够(课程目标):
- 描述调用栈和运行至完成规则,并解释为什么同步代码总是先于任何被推迟的回调执行完。
- 说出三个核心部件:调用栈、任务队列、事件循环,并说明
setTimeout的回调在哪里等待、由谁来运行。 - 用微任务队列及其「先彻底清空再取下一个任务」的规则,解释为什么 promise 的
.then()回调会先于setTimeout(fn, 0)运行。 - 解释
await实际做了什么:它只挂起自己所在的 async 函数,并把剩余部分安排成一个微任务,而不会阻塞线程。 - 预测一段混合了同步打印、
setTimeout、.then()和await的非平凡代码片段的精确输出顺序,然后在真实的 Node 或浏览器控制台里验证。
先修条件: 你会写 JavaScript 函数,会调用 console.log 和 setTimeout,并且至少在语法层面用过 .then() 和 async/await。不要求任何事件循环知识,不要求读过 HTML 规范,也不假设任何框架或构建工具。
练习环境: 你自己在 Node(node file.mjs)或浏览器 DevTools 控制台里运行这些代码片段,本课程没有内嵌运行时。每次预测都以你运行真实代码、对照自己的判断收尾。
课程目录
来源列表见 sources.md。