JavaScript虽然是单线程语言,但它借助事件循环实现了一种并发模型,使页面在等待网络请求或定时器时不至于完全卡死。要理解这个模型,我们需要从调用栈、任务队列以及微任务队列的关系入手。

什么是事件循环
事件循环是JavaScript运行时环境(如浏览器或Node.js)用来协调代码执行、事件处理和异步操作的机制。它不断检查调用栈是否为空,如果为空就从队列中取出任务执行。
调用栈与任务队列
当代码运行时,函数被推入调用栈,执行完再弹出。遇到异步操作(如setTimeout、fetch)时,相关回调被交给浏览器或Node的底层线程处理,处理完后回调函数进入任务队列等待。
宏任务与微任务
任务分为宏任务和微任务。宏任务包括script整体代码、setTimeout、setInterval等;微任务包括Promise.then、MutationObserver等。每执行完一个宏任务,就会清空所有微任务,再进行下一次宏任务。
| 类型 | 常见示例 | 执行时机 |
|---|---|---|
| 宏任务 | setTimeout, setInterval | 每次事件循环取一个 |
| 微任务 | Promise.then, queueMicrotask | 宏任务结束后立即清空 |
用代码观察执行顺序
下面这段代码能直观展示微任务优先于宏任务执行:
console.log('开始'); // 同步代码,立即执行
setTimeout(function() {
console.log('宏任务setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('微任务Promise');
});
console.log('结束');
// 输出顺序:
// 开始
// 结束
// 微任务Promise
// 宏任务setTimeout
为什么定时器不准时
因为setTimeout属于宏任务,它必须等调用栈清空且前面的宏任务都执行完才能运行。如果主线程被长任务占用,或者微任务队列一直不为空,回调就会被推迟。
总结
JavaScript的并发模型并不是多线程并行,而是基于事件循环的单线程调度。掌握宏任务与微任务的差别,可以让我们更准确地预测异步代码的执行结果,避免常见的逻辑错误。
JavaScript事件循环并发模型修改时间:2026-07-27 15:48:20