JavaScript 事件循环机制详解:同步、异步与宏微任务
本文深入解析 JavaScript 的单线程特性与事件循环机制。通过同步队列、异步队列以及宏任务(Macro Task)和微任务(Micro Task)的执行优先级,详细说明了 setTimeout 与 Promise 的执行顺序,并结合代码示例阐明控制台输出结果的生成逻辑。
前言
JavaScript 是一门单线程的弱类型语言,但在实际开发中,经常涉及需要异步处理或等待的操作。
例如 AJAX 请求,或者 ES6 中新增的 Promise 对象,这些常用于处理回调函数等场景。
概念
在 JavaScript 代码的执行过程中,任务可以被划分为同步队列和异步队列两类。
同步任务类似于立即执行函数,无需等待即可直接进行,它们直接进入主线程执行,类似于常规的函数调用。
异步队列则包含异步执行的函数,例如 AJAX 请求。在发起请求时,任务会进入异步队列,加载到任务中时需要等待,之后才能处理返回值。
实例分析
通过以下代码,我们可以初步了解事件循环机制的基本原理。
console.log('1');
setTimeout(function() {
console.log('4');
}, 0);
Promise.resolve().then(function() {
console.log('2');
}).then(function() {
console.log('3');
});
console.log('5');将代码打印到控制台,输出结果为:1,5,2,3,4。
我们知道,在 JavaScript 中,类似定时器以及 ES6 新增的 Promise 属于异步函数。回到上述队列的概念,可以得出 1 和 5 属于同步执行队列。
在同步队列中的代码执行完毕后,再执行异步队列中的代码。
提示
在解析异步队列中的 Promise 和定时器时,我们发现定时器 setTimeout 的执行晚于 Promise。这里引入 JavaScript 规范中的宏任务(Macro Task)和微任务(Micro Task)的概念。
在 JavaScript 中,宏任务包括:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境)。
微任务包括:Promise、MutationObserver、process.nextTick(Node.js 环境)。
回到上述定时器和 Promise 的问题,此时我们知道,当 JavaScript 中存在异步队列时,优先执行微任务,再执行宏任务。
进阶实例
假设在异步队列中还存在嵌套的异步队列,我们需要如何处理?
console.log(1);
setTimeout(function() {
console.log(5);
}, 10);
new Promise(resolve => {
console.log(2);
resolve();
setTimeout(() => console.log(3), 10);
}).then(function() {
console.log(4);
})
console.log(6);
将代码执行到控制台,得出的打印顺序是:1,2,6,4,5,3。
- 不同于第一个例子中的 Promise,打印 2 是优先于 6 执行的。由此可知,new Promise 在执行过程中,在未执行 resolve 或 rejected 前,所执行的代码均属于同步队列中的代码。
- 再看 4,5,3 的执行顺序,在执行微任务 Promise 的回调 resolve 之后,对应的 then 立即执行。
- 在打印结果中,定时器 5 优先执行于属于微任务 Promise 中的宏任务定时器 3。定时器 5 这个宏任务是在 Promise 微任务这个队列之后加入的,在 Promise 执行完成 then 回调之后,Promise 中的宏任务才加入到队列中,因此在定时器 5 之后执行。
总结
在 JavaScript 中,宏任务包括:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境)。
微任务包括:Promise、MutationObserver、process.nextTick(Node.js 环境)。
在执行过程中,同步代码优先于其他任务队列中的代码。
定时器、Promise 这类任务,在执行过程中,会先加入队列。
在执行完同步代码之后,再根据宏任务和微任务的分类,先执行微任务队列,再执行宏任务队列。
到此这篇关于 JavaScript 事件循环机制的文章就介绍到这了,更多相关 JS 事件循环机制内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
