Promises 的回调总是优先于 MutationObserver 的回调执行,因为 HTML 规范规定:每次宏任务结束后,先清空所有 Promise 微任务(含链式新产生的),再处理 MutationObserver 回调。

微任务队列中,Promises 的回调总是优先于 MutationObserver 的回调执行,即使它们在代码中看似“同时注册”。这是由 HTML 规范明确规定的执行顺序:所有已就绪的 Promise 回调(即已 resolve/reject 的 Promise 的 .then/.catch/.finally)会先清空,之后才处理 MutationObserver 的回调。
执行顺序规则
浏览器在每次宏任务(如 script 执行、setTimeout 回调、事件处理等)结束后,会按固定顺序处理微任务队列:
- 先执行所有已排队的 Promise 微任务(包括链式 .then 中新产生的)
- 再执行所有已触发但尚未回调的 MutationObserver 回调
- 这个顺序不会因注册先后或 DOM 变更时机而改变
典型混合场景示例
以下代码能清晰体现排序逻辑:
// 1. 创建并立即 resolve 一个 Promise
Promise.resolve().then(() => console.log('Promise 1'));
// 2. 创建 MutationObserver 并监听 body
const mo = new MutationObserver(() => console.log('MO'));
mo.observe(document.body, { childList: true });
// 3. 触发一次 DOM 变更(同步产生 mutation 记录)
document.body.appendChild(document.createElement('div'));
// 4. 再注册一个 Promise
Promise.resolve().then(() => console.log('Promise 2'));
输出一定是:
立即学习“Java免费学习笔记(深入)”;
Promise 1Promise 2MO
注意:虽然 DOM 变更发生在两个 Promise 之间,但 MO 回调仍排在所有 Promise 微任务之后。
为什么不是“谁先注册谁先执行”?
MutationObserver 的回调不直接进入微任务队列,而是被暂存为“mutation 记录列表”。只有当微任务队列(含所有 Promise)彻底清空后,浏览器才会检查该列表,并将对应的回调作为新的微任务入队——但此时 Promise 队列已空,所以它必然排在最后。
换句话说:Promises 是“即时入队、优先执行”,MutationObserver 是“延迟入队、统一调度”。
实际开发建议
- 不要依赖 MO 和 Promise 的交错时序做关键逻辑;如有严格先后需求,显式用 Promise 包裹 MO 回调(例如在 callback 里 return Promise.resolve())
- 若需确保 DOM 更新后立刻执行某段 JS(且比 MO 更早),可用
queueMicrotask—— 它和 Promise 同级,但语义更清晰 - 调试时可用
console.log+ 时间戳或performance.now()验证实际执行顺序


















