"深入理解 JavaScript 中的事件循环(Event Loop)机制"

前言

事件循环(event loop)是一种用于处理异步操作的编程模型。在 JavaScript 中,事件循环是指浏览器或 Node.js 运行时环境中负责管理执行顺序的机制。

简单来说,事件循环不断地监听事件队列,当事件队列中有任务时,会从中取出一个任务并执行。执行完当前任务后,再次检查事件队列,如此循环,直到事件队列为空。

这种机制使得 JavaScript 能够处理异步操作,例如定时器、网络请求、事件监听等,而不会阻塞主线程的执行。这样就实现了非阻塞的异步编程,提高了程序的性能和响应速度。

进程与线程

首先我们来了解一下什么是进程什么是线程。

进程是操作系统中的一个基本概念,它表示正在运行的一个程序的实例。每个进程都有自己独立的地址空间,包括代码、数据、堆栈等,同时还包括了进程所需的一些系统资源,比如文件描述符、信号处理设置等。进程之间一般是相互独立的,彼此不会影响。

线程是进程中的一个实体,是 CPU 调度和分派的基本单位。一个进程可以包含多个线程,这些线程共享进程的地址空间和系统资源,但每个线程有自己的调用栈和局部变量。多线程使得程序可以进行并发执行,提高了程序的效率和响应速度。

总结起来,进程是程序的执行实例,包含了程序的代码、数据和系统资源;而线程是进程中的执行单元,多个线程可以共享进程的资源,实现并发执行。

异步与同步

同步操作是指程序按照顺序依次执行,每个操作都要等待上一个操作完成后才能进行。换句话说,当一个操作在执行时,程序会阻塞,直到该操作完成后才会执行下一个操作。这种执行方式简单直观,但可能会导致程序的响应速度变慢,特别是在处理大量耗时操作时。

异步操作是指程序中的操作可以同时进行,不需要等待上一个操作完成才能进行下一个操作。异步操作通常会通过回调函数、Promise 或者 async/await 等机制来处理。这种执行方式可以提高程序的效率和响应速度,特别适合处理大量的I/O操作或网络请求。

宏任务与微任务

在异步中,又包括宏任务与微任务。

宏任务:script,setTimeout,setInterval,setImmediate,I/O,UI-rendering(ui渲染)

微任务:promise.then(),MutationObserver

Event-Loop执行顺序

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

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

3.如有则执行微任务

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

5.执行宏任务(下一次event loop的开始)

下面我们通过一段代码来更好的理解event-loop的执行顺序。

js 复制代码
console.log("stard")           //第一个输出stard
async function async1(){     //async 相当于new Promise,构造函数属于同步代码
    await async2()
    console.log("saync1 end");    !!!第一个进入微任务队列
}
async function async2(){
    console.log("saync2 end");  //第二个输出saync2 end
}
async1()
setTimeout(function(){      !!!第一个进入宏任务队列
    console.log("setTimeout");
},0)
new Promise((resolve)=>{
    console.log("promise");  //第三个输出promise
    resolve()
})
.then(()=>{                 !!!第二个进入微任务队列
    console.log("then1");
})
.then(()=>{                 !!!第三个进入微任务队列
    console.log("then2")
})
console.log("end");      //第四个输出end

--------------------------------------------------------------------------------------------------------------- 首先我们按照步骤来先执行同步代码(第一行,输出stard ),往下运行,async1和async2的函数声明不用运行,运行到第九行async1(),因为async相当于new Promise构造函数,属于同步代码,虽然await相当于.then的用法,但浏览器默认直接运行await所在语句,且await后一行代码会进入微任务队列(系统会创建两个队列,一个宏任务队列,一个微任务队列,先进先出原则)

直接执行await async2(),第二个输出saync2 end,此时运行到第十行,因为setTimeout属于宏任务,所以第一个进入宏任务队列

继续运行到第十三行,new Promise 构造函数属于同步代码,所以直接运行,第三个输出promise

继续运行到第十七行,(promise.then)属于微任务,所以先后两个.then都进入微任务

继续运行到第二十三行,同步代码直接运行,所以第四个输出end。

--------------------------------------------------------------------------------------------------------------- 此时同步代码执行结束,开始执行微任务,第一个进入微任务队列的是第四行代码,所以第五个输出saync1 end ,第二、三进入微任务的是两个.then,所以第六个输出的是then1,第七个输出的是then2 ---------------------------------------------------------------------------------------------------------------

此时异步中微任务队列也全部执行完毕,开始执行宏任务,而宏任务中只有第十行setTimeout,所以第八个输出的是setTimeout。

此时我们对event-loop的讲解就接近尾声了,那么现在有个疑问,event-loop中微任务一定比宏任务先执行嘛?

答案是错误的,因为第一步执行的同步代码也属于宏任务,所以简单来说,一次event-loop是由宏任务开始的也是由宏任务结束的


相关推荐
敲啊敲952716 分钟前
5.npm包
前端·npm·node.js
贵州晓智信息科技21 分钟前
如何优化求职简历从模板选择到面试准备
面试·职场和发展
CodeClimb25 分钟前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
咸鱼翻面儿29 分钟前
Javascript异步,这次我真弄懂了!!!
javascript
brrdg_sefg30 分钟前
Rust 在前端基建中的使用
前端·rust·状态模式
m0_748230941 小时前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端·rust·excel
qq_589568101 小时前
Echarts的高级使用,动画,交互api
前端·javascript·echarts
黑客老陈2 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安2 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite