解密 Event Loop:宏任务与微任务的奇妙旋律

前言

JavaScript是一门单线程的编程语言,这一特性决定了在任何给定时刻,JavaScript程序只能执行一个任务。然而,为了使JavaScript能够处理异步操作而不阻塞主线程,引入了Event Loop(事件循环)的机制。本文将深入探讨JavaScript的Event Loop,解释它的工作原理,并通过案例帮助新手更好地理解这一关键概念。

在学习Event Loop之前,我们先给大家科普些小知识

什么是单线程?

单线程是指在任何给定时刻,程序或进程只能执行一个任务或代码块。在单线程模型中,代码是按照顺序逐行执行的,每个操作都要等待前一个操作的完成。

什么是宏任务?

宏任务代表的是那些较大粒度的任务,通常包括I/O 操作、定时器事件(setTimeoutsetInterval)、用户交互事件(点击输入)等。每个宏任务都会在一个事件循环中执行,宏任务之间会按照一定的顺序排队执行。

js 复制代码
// 宏任务
let a = 2
console.log(a);

setTimeout(() => { 
    console.log(1);
}, 0);

let b = 3
console.log(b);

在上面的例子中,整体代码执行是同步的,虽然setTimeout设置了超时时间为0毫秒,但它仍然会被放入宏任务队列,而不是立即执行。这是因为setTimeout的第二个参数表示最少等待的时间,而非确切的时间。所以这个回调函数会在当前宏任务执行完毕后,被放入宏任务队列等待执行。

什么是微任务?

微任务是相对于宏任务更小粒度的任务,典型的微任务包括Promise的回调函数、process.nextTick等。微任务的执行时机是在当前宏任务执行完毕、下一个宏任务开始之前。

js 复制代码
console.log('start');
new Promise((resolve, reject) => {
  console.log('123');
  resolve();
})
// 微任务
.then(() => {
  console.log('then');
})
console.log('end');

在上面的例子中,Promise的构造函数是同步执行的。因此,这里会打印123到控制台。同时,通过resolve方法将 Promise 的状态设置为resolved。然后在then方法中注册了一个回调函数,这个回调函数会在微任务队列中等待执行。由于Promise的状态是同步设置为resolved的,所以这个微任务会立即执行。

宏任务与微任务执行顺序与优先级

在一个宏任务中,当所有同步代码和宏任务执行完毕后,会检查微任务队列,依次执行其中的微任务。然后,选择下一个宏任务执行,这个过程不断循环。

js 复制代码
console.log("Start");

setTimeout(() => {
  console.log("这是宏任务");
}, 0);

Promise.resolve().then(() => {
  console.log("这是微任务");
});

console.log("End");

在上述例子中,微任务的执行优先于下一个宏任务的开始,即使微任务是在当前宏任务中产生的。

什么是Event Loop?

Event Loop是JavaScript处理异步操作的核心机制。它使得JavaScript在执行同步任务的同时,能够异步执行一些任务,而不会阻塞主线程。这种机制通过一系列的步骤来实现,主要包括执行同步代码、执行异步代码、检查消息队列、执行消息队列中的任务等。

Event Loop的基本工作流程

1. 执行同步代码(这属于宏任务)

JS引擎首先会执行当前执行栈中的同步代码,这是按照代码的顺序逐行执行的部分。

2. 当执行栈为空,查询是否有异步代码需要执行

当执行栈为空时,JS 引擎会去查询是否有异步代码需要执行。这可以是注册的回调函数、定时器到期、事件触发等。

3. 执行微任务

如果有微任务(Promise 的回调、process.nextTick等),它们会在当前宏任务执行完毕后立即执行。微任务的执行时机优先于下一个宏任务开始。

4. 如果有需要,会渲染页面

在一些环境中,比如浏览器中,可能在这个时候进行页面的渲染。这确保了用户界面的及时更新。

5. 执行宏任务

如果有宏任务(定时器事件、I/O 操作、用户交互事件),它们会被放入宏任务队列中,等待下一轮 Event Loop 执行。

总结

整个过程是一个循环,不断地执行同步代码、查询异步任务、执行微任务、渲染页面以及执行宏任务。这个循环一直持续,形成了 JavaScript 异步执行的基本模型。

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
uhakadotcom9 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪10 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
快速开始使用 n8n
后端·面试·github
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github