JavaScript异步核心是Event Loop,它调度microtask(如Promise.then)优先于task(如setTimeout),Promise executor同步执行,async/await基于Promise实现非阻塞暂停恢复。

JavaScript异步编程的核心机制不是 Promise 或 async/await 本身,而是 Event Loop —— 它决定了回调何时执行、Promise 状态如何流转、async 函数如何暂停与恢复。
Event Loop 怎么调度 Promise.then 和 setTimeout
很多人以为 Promise.then 是“立即执行”,其实它被推入 microtask queue;而 setTimeout 的回调进的是 task queue(也叫 macrotask queue)。microtask 总是清空完才处理下一个 task。
这意味着:
-
Promise.then回调一定比同轮循环中的setTimeout先运行 - 连续多个
Promise.then会链式压入 microtask 队列,依次执行,不中断 JS 主线程 -
queueMicrotask可手动插入 microtask,行为和Promise.resolve().then()一致
console.log(1); Promise.resolve().then(() => console.log(2)); setTimeout(() => console.log(3), 0); console.log(4); // 输出:1 → 4 → 2 → 3
Promise 构造函数里的 executor 是同步执行的
写 new Promise((resolve, reject) => { ... }) 时,传入的函数会**立刻同步执行**,不是“等异步时机到了再调”。这是最容易误解的一点。
立即学习“Java免费学习笔记(深入)”;
常见误用场景:
- 在 executor 里直接
return而忘记调用resolve或reject→ Promise 永远 pending - 误以为
Promise自带“延迟”或“自动异步” → 实际上它只是对异步流程做状态封装 - 在 executor 中抛出未捕获错误 → 等价于
reject(new Error(...)),但不会触发全局unhandledrejection(除非没加 .catch)
new Promise(resolve => {
console.log('executor runs now'); // 立刻打印
resolve('done');
}).then(console.log); // 'done'
async/await 不是语法糖,而是 Generator + Promise + 状态机的组合实现
async 函数返回一个 Promise,await 并非阻塞线程,而是让出控制权,等右侧 Promise settled 后,再从上次暂停处继续执行(类似协程)。
关键细节:
-
await后面如果不是 Promise,会被自动包装成Promise.resolve(...) -
await只能在async函数内使用,顶层 await 仅在模块作用域(ESM)中合法 - 多个
await默认串行;想并发需用Promise.all([p1, p2])包一层 -
try/catch捕获的是 rejected Promise,不是 throw 的原始错误对象(但语义等价)
async function f() {
const a = await Promise.resolve(1); // 不是阻塞,是暂停+注册 microtask
const b = await Promise.resolve(2);
return a + b;
}
f().then(console.log); // 3
真正容易被忽略的是:Promise 链的错误传播依赖每个环节是否显式处理,而 async/await 的 try/catch 只覆盖当前 await 表达式——漏掉一个 catch,就可能让 rejection 逃逸成 unhandledrejection。这在复杂嵌套或条件分支中尤其危险。











