微任务在事件分发后执行,是因为 javascript 引擎将宏任务队列和微任务队列分开处理。每次从宏任务队列取出一个任务(如 settimeout)执行完毕后,引擎会清空当前微任务队列中的所有任务,然后才进入下一轮事件循环。

为什么 setTimeout 回调里打印的 DOM 元素是空的?
因为 setTimeout 的回调属于宏任务,它在 DOM 更新(同步代码)之后、下一次渲染之前执行。如果在回调中直接读取 DOM,拿到的还是旧状态。

const btn = document.getElementById('btn');
// 同步修改 DOM
document.body.innerHTML = '<button id="btn">Click</button>';
// 宏任务:此时 DOM 已更新,但尚未重绘
setTimeout(() => {
const newBtn = document.getElementById('btn');
console.log(newBtn); // <button id="btn">Click</button>
}, 0);
// 微任务:在宏任务前执行,DOM 还是旧的
Promise.resolve().then(() => {
const oldBtn = document.getElementById('btn');
console.log(oldBtn); // null
});
预期结果:
第一次 console.log 输出按钮元素。
第二次 console.log 输出 null。
如何确保在 DOM 更新后获取最新元素?
使用 MutationObserver 监听 DOM 变化,它会在 DOM 变更完成后触发,且其回调属于微任务级别,能捕获到最新的 DOM 状态。

const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
const btn = document.getElementById('btn');
console.log(btn); // <button id="btn">Click</button>
}
});
});
observer.observe(document.body, { childList: true });
// 同步修改 DOM
document.body.innerHTML = '<button id="btn">Click</button>';
预期结果:console.log 输出按钮元素。
基于 Promise.then 的执行时机问题
Promise.then 的回调总是作为微任务执行,即使 Promise 已经 resolved。这保证了它在当前宏任务结束后立即执行,而不是等待下一个宏任务。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











