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

相关推荐
影子落人间2 分钟前
已解决npm ERR! request to https://registry.npm.taobao.org/@vant%2farea-data failed
前端·npm·node.js
世俗ˊ26 分钟前
CSS入门笔记
前端·css·笔记
子非鱼92127 分钟前
【前端】ES6:Set与Map
前端·javascript·es6
6230_31 分钟前
git使用“保姆级”教程1——简介及配置项设置
前端·git·学习·html·web3·学习方法·改行学it
想退休的搬砖人40 分钟前
vue选项式写法项目案例(购物车)
前端·javascript·vue.js
加勒比海涛1 小时前
HTML 揭秘:HTML 编码快速入门
前端·html
啥子花道1 小时前
Vue3.4 中 v-model 双向数据绑定新玩法详解
前端·javascript·vue.js
麒麟而非淇淋1 小时前
AJAX 入门 day3
前端·javascript·ajax
茶茶只知道学习1 小时前
通过鼠标移动来调整两个盒子的宽度(响应式)
前端·javascript·css
清汤饺子1 小时前
实践指南之网页转PDF
前端·javascript·react.js