在 javascript 的事件循环中,微任务(microtask)是在当前宏任务(macrotask)执行完毕后、下一个宏任务开始前立即执行的。要实现这一行为,只需在当前同步代码或异步回调中使用 promise.then()、queuemicrotask() 或 mutationobserver 来调度任务,这些任务会被推入微任务队列,并在当前调用栈清空后优先于其他宏任务处理。

Promise.then() 如何确保在 DOM 更新后执行
Promise.then() 注册的回调会在当前同步代码块结束后、浏览器渲染前执行。这意味着如果在点击事件中修改了 DOM,通过 Promise.then() 访问的 DOM 状态将是更新后的最新值,而不是旧值。

const btn = document.getElementById('myButton');
btn.addEventListener('click', () => {
// 1. 同步修改 DOM
btn.textContent = 'Clicked';
// 2. 使用 Promise.then() 注册微任务
Promise.resolve().then(() => {
// 3. 此时 DOM 已更新,但尚未重绘
console.log('Button text:', btn.textContent); // 输出: Clicked
console.log('Is button clicked?', btn.classList.contains('active'));
});
});
上述代码展示了在点击事件处理程序中,先同步修改按钮文本,然后通过 Promise.then() 在微任务阶段读取该文本。由于微任务在当前宏任务(点击事件)结束后立即执行,因此能获取到最新的 DOM 状态。这常用于需要在 DOM 更新后但页面重绘前进行逻辑处理的场景,例如计算布局或触发某些副作用。
queueMicrotask() 与 MutationObserver 的执行时机对比
queueMicrotask() 是专门用于将函数加入微任务队列的 API,而 MutationObserver 则用于观察 DOM 变化并在变化发生后以微任务方式通知。两者都在当前宏任务结束后执行,但适用场景不同。

// 示例 1: queueMicrotask()
console.log('Start');
queueMicrotask(() => {
console.log('Microtask 1');
});
console.log('End');
// 输出顺序: Start, End, Microtask 1
// 示例 2: MutationObserver
const div = document.querySelector('div');
const observer = new MutationObserver((mutations) => {
console.log('Mutation observed');
});
observer.observe(div, { childList: true });
div.innerHTML = '<span>New</span>';
// 输出顺序: (无同步输出), Mutation observed
queueMicrotask() 直接调度一个函数作为微任务,适用于需要简单延迟执行的场景。而 MutationObserver 则监听 DOM 变化,当观察到变化时,其回调函数会以微任务形式执行。在实际开发中,如果需要响应 DOM 变化并执行后续逻辑,MutationObserver 是更合适的选择,因为它能自动检测变化并触发回调,而无需手动调度微任务。
微任务队列满时的行为表现
当微任务队列中存在大量任务时,JavaScript 引擎会持续执行微任务,直到队列为空。这意味着如果某个微任务又产生了新的微任务,这些新任务也会被立即执行,可能导致当前宏任务被长时间阻塞,影响页面响应性。
function generateMicrotasks(count) {
if (count === 0) return;
console.log(`Microtask ${count}`);
queueMicrotask(() => generateMicrotasks(count - 1));
}
console.log('Start');
generateMicrotasks(5);
console.log('End');
// 输出顺序: Start, Microtask 5, Microtask 4, Microtask 3, Microtask 2, Microtask 1, End
上述代码演示了递归生成微任务的情况。每个微任务都会产生一个新的微任务,导致微任务队列持续有任务可执行。最终,所有微任务执行完毕后,才会继续执行后续的同步代码(如 console.log('End'))。这种模式在需要批量处理数据时非常有用,但也需要注意避免无限递归或过深的调用链,以免导致性能问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











