promise.then 一定比 settimeout 先执行,前提是 promise 已处于 fulfilled 或 rejected 状态;因为 .then 是微任务,在当前宏任务结束后立即清空执行,而 settimeout 是宏任务,需等所有微任务完成后才执行。

Promise.then 一定比 setTimeout 先执行,但前提是 Promise 已经处于 fulfilled 或 rejected 状态。关键不在“谁写在前面”,而在于“谁的任务类型更优先”——微任务(Promise.then)总在当前宏任务结束后立即执行,宏任务(setTimeout)必须等所有微任务清空后才轮到。
同步代码永远最先跑完
JavaScript 执行时,先一股脑把所有同步语句执行完,包括:
– console.log 直接输出
– new Promise 的 executor 函数(即 resolve/reject 前的那部分)
– async 函数中 await 之前的部分
这些都属于“当前宏任务的主线程内容”,不进任何队列,立刻执行。
Promise.then 是微任务,不是“马上执行”
Promise 构造函数里的代码是同步的,但 .then 回调不是。
它会被推入微任务队列(microtask queue),等待当前宏任务彻底结束(包括所有同步代码 + 同步产生的其他微任务)后,一次性清空整个微任务队列。
常见误区:
– 写了 .then 就以为会立刻执行?错,得等 Promise 状态已确定(resolve/reject 已调用)
– 多个 .then 链式调用,会按顺序依次加入微任务队列,不会穿插宏任务
setTimeout 是宏任务,哪怕设为 0ms 也得排队
setTimeout 的回调被放入宏任务队列(macrotask queue),它不会插队:
– 当前宏任务(比如整个 script 脚本)执行完 →
– 清空全部微任务 →
– 才轮到取第一个宏任务(可能是这个 setTimeout)执行
所以即使写成 setTimeout(..., 0),它也一定排在所有已注册的 Promise.then 之后。
典型题目还原(带注释执行流)
代码:
console.log('start');
setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('Promise'));
console.log('end');
执行顺序解析:
→ 'start'(同步)
→ 注册 setTimeout 宏任务(暂存)
→ Promise.resolve() 立即 fulfilled,.then 回调入微任务队列
→ 'end'(同步)
→ 同步代码结束,开始处理微任务:执行 .then → 输出 'Promise'
→ 微任务队列清空,进入下一轮事件循环:取出 setTimeout 回调 → 输出 'setTimeout'











