在 javascript 的事件循环中,微任务(microtask)会在当前宏任务(macrotask)执行完毕后的“检查点”立即执行,且优先级高于后续的 dom 渲染和下一个宏任务。要实现这一行为,只需将需要延后执行的逻辑包裹在 promise.then()、mutationobserver 或 queuemicrotask() 中即可。当同步代码或当前事件处理器中的同步部分运行结束时,引擎会清空整个微任务队列,然后再去处理下一轮事件循环。

为什么 Promise 回调比 setTimeout 更先执行
因为 setTimeout 注册的是宏任务,而 Promise 的回调是微任务。宏任务必须等待当前调用栈清空并进入下一轮事件循环才能执行,而微任务在当前调用栈清空后立即执行。这意味着即使 setTimeout 的延迟时间设为 0,它也必须等待所有微任务执行完毕后才会被调度。

console.log('1. Start');
setTimeout(() => {
console.log('4. Timeout');
}, 0);
Promise.resolve().then(() => {
console.log('3. Promise');
});
console.log('2. End');
上述代码的执行顺序为:1. Start → 2. End → 3. Promise → 4. Timeout。这证明了微任务在同步代码结束后、宏任务开始前执行。
async/await 如何影响执行顺序
async/await 是基于 Promise 的语法糖,因此 await 关键字后面的代码也会作为微任务排队。在事件处理器中,如果使用了 await,其后的代码不会阻塞当前线程,而是让出控制权给其他同步代码,待微任务队列清空时再恢复执行。这与直接使用 Promise.then() 的行为一致,但代码结构更线性。
使用 ImageMagick 的 convert 和 mogrify 命令进行批量图像处理,支持调整大小、裁剪、水印和格式转换。与 libvips 集成以实现高性能缩略图生成。

async function handleEvent() {
console.log('A. Start async');
await new Promise(resolve => resolve());
console.log('C. After await');
}
console.log('B. Before call');
handleEvent();
console.log('D. End sync');
该程序的输出顺序为:A. Start async → B. Before call → D. End sync → C. After await。await 之后的代码被推入微任务队列,在所有同步代码(包括 B 和 D)执行完后才运行。
微任务队列耗尽前是否会触发 UI 渲染
不会。浏览器保证在一次事件循环的检查点中,微任务队列会被完全清空,期间不会插入任何 UI 渲染或用户交互处理。只有当微任务队列为空时,浏览器才会进行重排(Reflow)和重绘(Repaint),然后才开始处理下一个宏任务。如果在微任务中频繁修改 DOM,这些修改会合并到下一次渲染帧中,而不是立即反映在屏幕上。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










