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

前言

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

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

什么是单线程?

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

什么是宏任务?

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

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 异步执行的基本模型。

相关推荐
莫西干式秃头14 分钟前
用 AI + threejs 写了个浏览器里的 3D 动作游戏《武来》:砍怪、放技能、开 SU7
前端·人工智能·three.js
kyriewen28 分钟前
我测了 6 种防请求竞态的写法:只有 1 种真能打
前端·javascript·程序员
孟健31 分钟前
用 WorkBuddy 做个人名片网页,挂上开源设计技能后效果完全不同了
前端·人工智能·ai编程
IT_陈寒35 分钟前
SpringBoot自动配置的坑,这次终于爬出来了
前端·人工智能·后端
OpsEye1 小时前
企业大模型压测,需要重点关注哪些指标?
javascript·ai编程
LuHang2 小时前
从天地图切换到高德地图:一次真实的底图迁移实战
前端·vue.js·cesium
用户360055579002 小时前
Kestrel_VLLM - 27 · 寄存器常驻与融合发射:两次「少发一次」
前端
前端小万2 小时前
用"道法术器"重构你和 AI 的协作方式
前端·人工智能·程序员
鶴哥只手遮天2 小时前
Angular 22 源码级深度解析-第 06 章 模板指令全解:`ɵɵelementStart`、`ɵɵproperty`、`ɵɵadvance` 与绑定指令
前端·开源·angular.js
D e re k ZH2 小时前
C++ 并发、未定义行为与工程化难点(No 3)
数据结构·c++·算法·面试