事件循环中的宏任务以及微任务
事件循环(Event Loop)
JavaScript 是一种单线程语言,意味着它一次只能执行一个任务。然而,由于现代应用程序需要处理大量异步操作(例如网络请求、定时器等),事件循环成为了处理这些操作的关键。
事件循环的概念是指 JavaScript 引擎中的一个机制,它负责管理调度代码的执行顺序。事件循环由两个阶段组成:宏任务队列和微任务队列。
事件循环是 JavaScript 引擎中的一种机制,用于协调和处理异步任务的执行顺序。它的核心是一个循环,不断地从任务队列中取出任务并执行,直到任务队列为空。事件循环分为以下几个阶段:
-
执行栈(Execution Stack) :JavaScript 引擎使用执行栈来管理代码的执行。当调用一个函数时,会将该函数放入执行栈中,然后执行其中的代码。当函数执行完毕后,会从执行栈中移除该函数。
-
宏任务队列(Macrotask Queue) :宏任务队列用于存放宏任务,在事件循环中执行。当执行栈为空时,事件循环会从宏任务队列中取出一个宏任务,放入执行栈中执行。
-
微任务队列(Microtask Queue) :微任务队列用于存放微任务,在宏任务执行完毕后立即执行。微任务队列的优先级高于宏任务队列,即在执行微任务时,不会执行宏任务。
-
渲染(Rendering) :在浏览器环境中,事件循环还负责处理页面的渲染。在执行完微任务后,会进行页面的重新渲染,然后等待下一个宏任务的执行。
事件循环的执行过程
事件循环的执行过程可以总结如下:
- 执行当前宏任务的同步代码,直至遇到异步任务。
- 将异步任务加入相应的任务队列中(宏任务队列或微任务队列)。
- 执行微任务队列中的所有微任务。
- 渲染页面。
- 从宏任务队列中取出一个宏任务,放入执行栈中执行。
- 重复以上步骤,直至所有任务执行完毕。
宏任务(Macro Tasks)
宏任务代表着 JavaScript 运行时环境中的一个主要工作单元。常见的宏任务包括:
-
整体代码块(Script)执行: 这是执行整个 JavaScript 代码的过程,通常从头到尾执行,除非在执行期间发生了异步操作。
-
定时器(setTimeout、setInterval)回调: 当计时器达到设定的时间后,相关的回调函数会被放入执行队列中作为一个宏任务。
-
事件处理: 例如,用户交互事件(点击、滚动等)或网络事件(请求响应、连接建立等)触发的回调会作为宏任务。
-
I/O 操作: 诸如文件读取、数据库操作等异步 I/O 任务也会被放入宏任务队列中。
微任务(Micro Tasks)
微任务是宏任务执行结束后立即执行的任务。常见的微任务包括:
-
Promise 的回调函数: 当 Promise 被解决(resolved)或拒绝(rejected)时,相关的回调会被放入微任务队列中等待执行。
-
MutationObserver 的回调函数: 当 DOM 发生变化时,相关的回调会被放入微任务队列中等待执行。
代码示例
console.log('Script Start');
setTimeout(function() {
console.log('Timeout');
}, 0);
Promise.resolve().then(function() {
console.log('Promise 1');
}).then(function() {
console.log('Promise 2');
});
console.log('Script End');
这段代码的执行顺序是什么?
-
首先,输出 "Script Start"。
-
接着,setTimeout 的回调函数被放入宏任务队列。
-
Promise.resolve().then 的第一个回调函数被放入微任务队列。
-
输出 "Script End"。
-
当前宏任务执行结束,检查微任务队列,执行微任务 "Promise 1"。
-
继续执行微任务队列,执行微任务 "Promise 2"。
-
最后,执行宏任务队列中的 setTimeout 回调函数,输出 "Timeout"。
转载自:https://juejin.cn/post/7377697380215013413