在 javascript 事件循环中,微任务(如 promise.then、queuemicrotask)会在当前宏任务(如 settimeout、dom 事件回调)执行完毕后、ui 渲染前立即执行。要实现事件绑定后执行微任务,只需在事件处理函数内部调用微任务 api,例如使用 promise.resolve().then() 或 queuemicrotask(),这样微任务会被推入微任务队列,并在当前同步代码结束后优先于下一个宏任务执行。

如何确保微任务在 DOM 事件回调中执行
在 DOM 事件回调中,直接调用 queueMicrotask 是最简洁的方式。它会将回调加入微任务队列,确保在当前事件处理函数同步部分结束后立即执行,而不会等待下一个宏任务。以下是一个完整的示例,演示点击按钮后触发微任务并更新页面内容。
<meta charset="UTF-8"><title>Microtask in Event</title><button id="btn">Click Me</button>
<p id="output">Initial</p>
<script>
const btn = document.getElementById('btn');
const output = document.getElementById('output');
btn.addEventListener('click', () => {
console.log('Event callback start');
queueMicrotask(() => {
console.log('Microtask executed');
output.textContent = 'Updated by microtask';
});
console.log('Event callback end');
});
</script>
运行上述代码并点击按钮,控制台将按顺序输出:Event callback start、Event callback end、Microtask executed。页面文本随后更新为“Updated by microtask”。这证明微任务在当前事件回调的同步代码结束后立即执行。
对比 Promise.then 与 queueMicrotask 的执行时机
Promise.resolve().then() 和 queueMicrotask() 都属于微任务,它们在事件循环中的执行时机相同,都在当前宏任务结束后、下一轮宏任务开始前执行。区别在于 API 的语义和使用场景:queueMicrotask 更轻量,适合单纯调度异步操作;Promise.then 则用于处理异步结果链式调用。以下代码对比两者在事件回调中的行为。
<meta charset="UTF-8"><title>Microtask Comparison</title><button id="btn1">Queue Microtask</button>
<button id="btn2">Promise Then</button>
<p id="out1">Btn1: Initial</p>
<p id="out2">Btn2: Initial</p>
<script>
const btn1 = document.getElementById('btn1');
const btn2 = document.getElementById('btn2');
const out1 = document.getElementById('out1');
const out2 = document.getElementById('out2');
btn1.addEventListener('click', () => {
console.log('Btn1 sync start');
queueMicrotask(() => {
console.log('Btn1 microtask');
out1.textContent = 'Btn1: Updated';
});
console.log('Btn1 sync end');
});
btn2.addEventListener('click', () => {
console.log('Btn2 sync start');
Promise.resolve().then(() => {
console.log('Btn2 microtask');
out2.textContent = 'Btn2: Updated';
});
console.log('Btn2 sync end');
});
</script>
分别点击两个按钮,控制台输出顺序均为:对应按钮的 sync start、sync end、microtask。页面文本随后更新。这表明两者在事件回调中作为微任务的执行时机完全一致,均在当前同步代码结束后立即执行。
当微任务中抛出异常时会发生什么
如果在微任务回调中抛出未捕获的异常,该异常会中断后续微任务的执行,并触发全局错误处理机制。以下代码演示在微任务中抛出异常的情况,验证异常对微任务队列的影响。
<meta charset="UTF-8"><title>Microtask Exception</title><button id="btn">Trigger Exception</button>
<p id="output">Initial</p>
<script>
const btn = document.getElementById('btn');
const output = document.getElementById('output');
btn.addEventListener('click', () => {
console.log('Start');
queueMicrotask(() => {
console.log('First microtask');
throw new Error('Test error');
});
queueMicrotask(() => {
console.log('Second microtask');
output.textContent = 'Updated';
});
console.log('End');
});
window.onerror = (msg) => {
console.log('Global error caught:', msg);
};
</script>
点击按钮后,控制台输出:Start、End、First microtask、Global error caught: Test error。Second microtask 不会被执行,页面文本保持“Initial”。这证明微任务中抛出的异常会终止后续微任务,并由全局错误处理器捕获。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











