Promise.race 这个 API,许多人第一反应会把它与 .then() 划等号,误以为它也会生成微任务。实际上并不如此——它本身并不创建微任务,只是同步监听多个 Promise 的首个状态变化,然后把那个结果(无论是 fulfilled 还是 rejected)直接“透传”给它的返回 Pro
Promise.race异步调度机制与微任务优先级
时间:2026-07-07
浏览:138
文章目录
Promise.race 这个 API,许多人第一反应会把它与 .then() 划等号,误以为它也会生成微任务。实际上并不如此——它本身并不创建微任务,只是同步监听多个 Promise 的首个状态变化,然后把那个结果(无论是 fulfilled 还是 rejected)直接“透传”给它的返回 Promise。真正决定调度顺序的,是被 race 的那些 Promise 内部的状态变更时机,而后续的 .then() 回调,依然是标准的微任务。

Promise.race 不是微任务的发起者
与 .then() 不同,Promise.race() 调用本身是同步执行的。它不会立即往微任务队列里塞任何回调。它只做一件事:为传入的每个 Promise 实例注册一个内部“完成监听器”。当其中任意一个 Promise 状态变为 fulfilled 或 rejected 时,race 返回的那个新 Promise 就会以相同结果立即 settle(即进入 fulfilled 或 rejected 状态)。这个 settle 动作会触发后续链式调用(比如 .then())的回调——而这些回调,才是真正的微任务。
实际执行顺序由被 race 的 Promise 决定
race 的“竞速”结果,完全取决于哪个被监听的 Promise 最先完成其状态变更逻辑。关键点在于:
- 如果某个 Promise 在构造函数中直接
resolve('a'),那它属于同步 resolve,其.then()回调会在当前宏任务末尾、微任务阶段执行; - 如果另一个 Promise 是
setTimeout(() => resolve('b'), 0),那它的 resolve 会发生在下一个宏任务,因此它的.then()一定晚于前者; - 所以
Promise.race([syncP, timeoutP])的结果一定是 syncP 的值,且 race 返回的 Promise 的.then()会排在本轮微任务队列靠前位置。
race 后续的 .then 是标准微任务
一旦 race 返回的 Promise 状态确定,你对其调用的 .then()、.catch() 就和普通 Promise 一样:回调被放入微任务队列,等待当前同步代码执行完毕后统一清空。例如:
console.log('1');
Promise.race([
Promise.resolve('fast'),
new Promise(r => setTimeout(() => r('slow'), 10))
]).then(v => console.log('2:', v));
console.log('3');
输出顺序是 1 → 3 → 2: fast,因为 .then() 是微任务,严格遵循“同步 → 微任务 → 宏任务”的事件循环规则。
常见误用:把 race 当作“强制提前结束”工具
需要警惕的是,race 不会取消或中断其他仍在运行的 Promise。它只关心“谁第一个完成”,其余 Promise 继续执行,可能产生副作用(比如多余的网络请求、未清理的定时器)。若需真正取消,应配合 AbortController 或手动设计可取消逻辑,不能依赖 race 本身。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。