事件循环Event Loop

news/2024/11/24 7:39:33/

什么是事件循环(event loop)

主线程不断的从消息队列中获取消息,执行消息,这个过程被称为事件循环,在javaScript中就是采用事件循环来解决单线程带来的问题

线程和进程

进程:计算机已经运行的程序,是操作系统管理程序的一种方式,我们可以认为,启动一个应用程序,就会默认启动一个进程(也可能是多个进程);
线程:操作系统能够运行运算调度的最小单位,通常情况下它被包含在进程中,每一个进程中,都会启动至少一个线程用来执行程序中的代码,这个线程被称之为主线程;

目前多数浏览器其实都是多进程的,默认当我们打开一个tab页面时就会开启一个新的进程,这是为了防止一个页面卡死而造成所有页面无法响应,整个浏览器需要强制退出

同步任务

在主线程上排队执行的任务,只有前一个任务执行完毕才能执行后一个任务

异步任务

不进入主线程而进入任务队列的任务,只有【任务队列】通知主线程,某个异步任务可以执行了,该任务才会进入主线程。

宏任务队列可以有多个,微任务队列只有一个

浏览器中的Event Loop

当 JS 引擎去执行 JS 代码的时候会从上至下按顺序执行,当遇到异步任务的,就会交由浏览器的其他线程去执行,处理完成就会通知事件触发线程将回调方法推送至事件任务队列的列尾,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行

宏任务队列(macro-task):setTimeOut、setInterval、<script></script> 整体代码、UI渲染、ajax
微任务队列(micro-task): Promise.then()或catch()、queueMicrotask()、MutationObserver

Node中的Event Loop

Node.js的运行机制如下:V8引擎解析JavaScript脚本。解析后的代码,调用Node API。libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎

宏任务(macro-task):setTimeOut、setInterval、IO事件、setImmediate、close事件
微任务(micro-task): Promise.then()或catch()、queueMicrotask()、process.nextTick

liubv引擎Event Loop的6个阶段介绍

timers 阶段

这个阶段执行timer(setTimeout、setInterval)的回调

timers是事件循环的第一个阶段,当我们使用setTimeOut或者是setInterval时,node会检查timers堆中有无过期的timer,如果有则依次执行

需要注意的是node不能保证到了过期时间就立即执行回调函数,因为他在执行回调前必须检查timer是否过期,检查的时候是需要消耗时间的,他可能不会立即看到过期的timer,从而略过,检查时间的长短取决于系统性能,性能越好执行的速度越快,另外一点是如果Event Loop中还有别的进程在执行,也会影响timer回调执行。
这与浏览器的Event Loop机制是类似的,浏览器环境中如果定时器在一个非常耗时的for循环之后运行,虽然时间已过期,仍要等到for循环计算完成才会执行定时器

在达到过期时间之间的时间称为有效期,定时器能够保证的就是在有效期内不会触发定时器

pending callbacks(pending callbacks) 阶段

这个阶段主要是执行某些系统层级操作的回调函数。比如说,TCP发生错误时候的错误回调。

idle 阶段

仅node内部使用。

prepare 阶段

只是表达空闲、预备状态(第二阶段结束,poll未触发之前)

poll 阶段:

检索新的I/O事件,执行I/O相关回调, 适当的条件下node将阻塞在这里

poll阶段主要有两个功能

  1. 根据不同的操作系统的实际情况来计算轮询I/O的时间。
  2. 处理poll队列中的事件

如果poll queue不为空且没有到达限制,event loop将同步执行queue里的callback,直至queue为空,或执行的callback达到系统上限。

如果 poll queue为空,且代码未设定timer,将会发生下面情况:

  1. 如果setImmediate()设定了callback,event loop将结束poll阶段进入check阶段并执行回调
  2. 如果没有setImmediate回调,event loop将阻塞在该阶段等待回调加入到队列,然后立即执行

如果代码设定timer了,poll queue为空,event loop将检查times,如果有times时间已经到达,event loop将按循环进入times阶段执行timer queue

check 阶段

在轮询I/O之后执行一些事后工作,通常是执行 setImmediate() 的回调

这个阶段允许poll阶段结束后立即执行回调,如果poll阶段空闲并且有setImmediate回调,那么将结束poll阶段进入check阶段执行回调

setImmediate实际上是一个特殊的timer,跑在事件循环中的一个独立阶段,他使用libuv的API来设定poll阶段之后立即执行回调

close callbacks 阶段

执行一些关闭的回调函数,如执行 socket 的 close 事件回调

liubv引擎Event Loop的6个阶段执行

在这里插入图片描述

在node.js里,任何异步方法(除timer,close,setImmediate之外)完成时,都会将其callback加到poll queue里,并立即执行

event loop 的每个阶段都有一个该阶段对应的队列和一个microtask队列
一个阶段执行完毕进入下一个阶段之前,Event Loop会先清空microtask队列的任务(如果有nextTick队列,则先清空nextTick队列然后再清空microtask队列),等到microtask队列清空后再进入下一个阶段
当所有阶段被顺序执行一次后,称 event loop 完成了一个 tick

延伸问题

为什么js是单线程

这主要和js的用途有关,js是作为浏览器的脚本语言,主要是实现用户与浏览器的交互,以及操作dom;这决定了它只能是单线程,否则会带来很复杂的同步问题。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。

浏览器多进程架构

###
下面主要介绍一下核心进程渲染进程

渲染进程(核心进程)

GUI线程

渲染布局

*主要负责页面的渲染,解析HTML、CSS,构建DOM树,布局和绘制等
*当页面需要重绘或者由于某种操作引发回流(重排)时,将执行该线程
*该线程与js引擎线程互斥,当执行js引擎线程时,GUI渲染会被挂起,当任务队列空闲时,主线程才会去执行GUI渲染

js引擎线程

解析、执行js,与GUI线程互斥

定时器触发线程

负责执行定时器的线程,如setTimeOut、setInterval

事件触发线程

主要负责将准备好的事件交给js引擎线程执行
如定时器结束,ajax等异步请求成功并触发回调函数,或者用户触发点击事件时,该线程会将待发事件依次加入任务队列队尾,等待js引擎线程执行

异步HTTP请求线程

负责执行异步请求一类的函数线程,如Promise、axios。

参考文档

https://github.com/nodejs/help/issues/1118
https://cloud.tencent.com/developer/article/2137582
https://www.jianshu.com/p/71defc1226c8
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
https://blog.csdn.net/weixin_44685906/article/details/124636886


http://www.ppmy.cn/news/69552.html

相关文章

iOS开发系列--Swift语言

概述 Swift是苹果2014年推出的全新的编程语言&#xff0c;它继承了C语言、ObjC的特性&#xff0c;且克服了C语言的兼容性问题。Swift发展过程中不仅保留了ObjC很多语法特性&#xff0c;它也借鉴了多种现代化语言的特点&#xff0c;在其中你可以看到C#、Java、Javascript、Pyth…

面试必问网络 - dos 攻击 和 ddos 攻击是什么,如何防范

1、DoS 攻击 和 DDoS 攻击的是什么 DoS 攻击&#xff1a; DoS&#xff08;Denial of Service&#xff0c;拒绝服务&#xff09; DoS 攻击通常由单个攻击者发起&#xff0c;通过向目标系统发送大量请求或特质的恶意数据包&#xff0c;使目标系统的资源耗尽&#xff0c;从而导…

【连续介质力学】张量的性质2

张量的代数操作 张量的性质 张量迹 Tensor Trace 定义 e ^ i ⨂ e ^ j \hat e_i \bigotimes \hat e_j e^i​⨂e^j​的迹: T r ( e ^ i ⨂ e ^ j ) e ^ i ⋅ e ^ j δ i j Tr(\hat e_i \bigotimes \hat e_j) \hat e_i \cdot \hat e_j \delta_{ij} Tr(e^i​⨂e^j​)e^i​⋅…

南京邮电大学Web技术双语实验一(客户端HTML脚本编写)

文章目录 一、 实验目的和要求二、实验环境(实验设备)三、实验原理及内容&#xff08;一&#xff09;编写个人主页&#xff08;二&#xff09;计算方程的两个根 四、实验小结&#xff08;包括问题和解决方法、心得体会、意见与建议等&#xff09;&#xff08;一&#xff09;实验…

NEFU-2023-JAVA实验八

实验目的 理解基于IO流文件操作的过程及意义 理解并掌握基于字节数组缓冲区&#xff0c;实现IO操作方法 理解并掌握基于NIO文件目录的创建方法 理解并掌握基于NIO文件创建的创建方法 理解并掌握基于NIO文件的删除方法 实验内容 需求 &#xff08;1&#xff09;按要求实现IOTest…

深度学习-第T5周——运动鞋品牌识别

深度学习-第T5周——运动鞋品牌识别 深度学习-第T5周——运动鞋品牌识别一、前言二、我的环境三、前期工作1、导入数据集2、查看图片数目3、查看数据 四、数据预处理1、 加载数据1、设置图片格式2、划分训练集3、划分验证集4、查看标签 2、数据可视化3、检查数据4、配置数据集 …

git的学习3

文章目录 一、git status 命令二、git diff 命令三、git commit 命令四、git reset 命令五、git rm 命令六、git mv 命令七、提交日志1、Git 查看提交历史2、git blame 总结 提交与修改部分 一、git status 命令 git status 命令用于查看在你上次提交之后是否有对文件进行再次…

360+ChatGLM联手研发中国版“微软+OpenAI”

文章目录 前言360与智谱AI强强联合什么是智谱AI360智脑360GLM与360GPT大模型战略布局写在最后 前言 5月16日&#xff0c;三六零集团&#xff08;下称“360”&#xff09;与智谱AI宣布达成战略合作&#xff0c;双方共同研发的千亿级大模型“360GLM”已具备新一代认知智能通用模…