前端学习笔记--Event-loop

定义

  • Event Loop:即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。

  • **进程:**进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础,进程是线程的容器(来自百科)。进程是资源分配的最小单位。我们启动一个服务、运行一个实例,就是开一个服务进程,例如 Java 里的 JVM 本身就是一个进程,Node.js 里通过 node app.js 开启一个服务进程,多进程就是进程的复制(fork),fork 出来的每个进程都拥有自己的独立空间地址、数据栈,一个进程无法访问另外一个进程里定义的变量、数据结构,只有建立了 IPC 通信,进程之间才可数据共享。

  • **线程:**是操作系统能够进行运算调度的最小单位,首先我们要清楚线程是隶属于进程的,被包含于进程之中。一个线程只能隶属于一个进程,但是一个进程是可以拥有多个线程的

浏览器模型

  • 浏览器是一个多进程模型,每个页卡都是一个独立的进程

  • 常见的线程:

    • GUI渲染(页面渲染:绘制、绘图、3d动画)
    • JS渲染引擎(执行js代码)
    • 事件触发线程 EventLoop
    • webApi也会创建线程 事件、定时器、ajax请求
    • webWorker
  • Chrome中的线程模型:

    • Chrome中发起HTTP发起请求最多可以使用6个并发的线程。
    • Chrome中负责向页面中执行绘制任务(执行HTML/CSS/JS代码)的只有一个线程——UI主线程。

宏任务(MacroTask)与微任务(微任务)

  • 宏任务
    • 执行脚本 script
    • setTimeout
    • setInterval
    • setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN
    • I/O (文件读写)
    • UI Rendering
    • Ajax
    • MessageChannel
  • 微任务
    • promise
    • Process.nextTickNode独有)
    • Object.observe(废弃)
    • MutationObserver
  • 渲染相关(不算事件环里的事件)
    • requestAnimationFrame(页面渲染之前执行)
    • requestIDleCallback(空闲时间执行)

Event Loop

  • Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。
  • JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。
  • Javascript单线程任务被分为同步任务异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
  • 执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务(microTask)队列是否为空,如果为空的话,就执行Task(宏任务),否则就一次性执行完所有微任务。 每次单个宏任务执行完毕后,检查微任务(microTask)队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务(microTask)后,设置微任务(microTask)队列为null,然后再执行宏任务,如此循环。
  • Event Loop流程
    • 先执行script脚本,将宏任务和微任务进行分类,如果调用的是浏览器的api,浏览器会开一个线程,等时间到了,会自动的放到宏任务队列中,微任务是直接放到微任务队列中
    • js执行完毕后,会清空所有的微任务,如果微任务再产生微任务,会放到当前微任务队列的尾部。
    • 如果页面需要渲染,则会执行渲染流程
    • Event Loop会不断扫描宏任务队列,如果宏任务队列中有回调,获取出来执行一个,继续执行上诉过程
    • 宏任务每次调用一个,微任务是清空所有
    • 浏览器渲染时机:在执行script和当前script中产生的微任务之后,浏览器渲染。而当前script产生的宏任务会在渲染之后执行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例题:

console.log(1);
async function Async() {
    console.log(2);
    await console.log(3);
    console.log(4);
}
setTimeout(() => {
    console.log(5);
}, 0)
const promise = new Promise((resolve, rejrct) => {
    console.log(6);
    resolve(7);
})
promise.then((res) => {
    console.log(res);
})
Async();
console.log(8);

答案:

1
6
2
3
8
7
4
5

在异步函数中,可将

async function f() {
  await p
  console.log('ok')
}

简化理解为:

function f() {
  return RESOLVE(p).then(() => {
    console.log('ok')
  })
}

在执行脚本时:先从上往下一次执行同步任务,也就是

console.log(1);
console.log(6);
console.log(2);
console.log(3);
console.log(8);

此时微任务队列依次中包括:

promise.then((res) => {
    console.log(res);
})
console.log(4);

宏任务包括:

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

当script执行完毕时,查询微任务,微任务将按入队先后顺序依次执行。微任务清空以后,查询宏任务队列,取出第一个宏任务,执行其回调。

Node.js Event Loop

NodeJS中的EventLoop使NodeJS能够进行非阻塞的I/O操作,尽管JavaScript是单线程的,可以通过将I/O操作交给系统内核去执行。

当某个I/O操作结束的时候,内核会将对应的callback函数元信息交给NodeJS中的poll queue(轮询队列)。

概述

当NodeJS开始工作的时候就会初始化EventLoop机制,处理我们的JavaScript脚本。当我们的脚本中调用了异步函数,计时器或者process.nextTick()的时候,EventLoop机制就会开始介入。

下图简明地展示了EventLoop的操作顺序:

   ┌───────────────────────────┐
┌─>│           timers          │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │
   └───────────────────────────┘

上面的每个方格展示了EventLoop的不同阶段。对应上文中的task queue,代表不同的taskQueue在不同阶段的处理机制。

每个阶段都维持着一个先进先出的回调函数队列。每个阶段都有特殊的职能,当EventLoop执行到该阶段的时候,会将该时刻在该阶段的队列中存在的所有回调函数执行完或者执行到回调函数数量的上限(NodeJS自己规定的参数),然后跳转到下一个阶段。

由于脚本中的某些操作会调度更多的操作,在poll(轮询)阶段新事件是由内核排队。因此在处理poll阶段事件的时候可以将其他的事件加入到poll阶段中。因此,长时间运行回调函数会让poll阶段的运行时间比计时器规定的阈值长地多,我们设定的计时阈值不一定准确在该时刻执行。

阶段描述

timers(计时阶段):这个阶段执行由setTimeout() 和 setInterval() 调度的回调。

pending callbacks(回调待处理阶段):这个阶段执行延迟到下一次循环迭代的I/O回调。

idle, prepare(闲置阶段):仅仅被NodeJS内部使用。(这里是根据官方文档描述的,不能甚解)

poll(轮询阶段):这个阶段检索I/O事件,执行I/O事件对应的回调函数(除了关闭回调、计时器调度的回调和 setImmediate() 之外的几乎所有异步操作),都将会在这个阶段被处理。

check(检测阶段):setImmediate()函数的回调函数将会在这里被处理。

close callbacks(关闭回调阶段):例如:socket.on('close', ...)

每个阶段都有对应的异步操作,当异步操作需要触发回调函数的时候是先将回调函数放在对应阶段的queue中,等待EventLoop机制进入到该阶段再去执行queue中排好队的回调函数。放入队列中的是回调函数的元信息。

timers(计时阶段)

计时器指定可以执行提供的回调的阈值,但是这个阈值不一定是人们希望执行的确切时间。当执行到setTimeout() 和 setInterval(),经过指定的时间阈值之后,Timers queue中对应的回调函数将会尽快被执行。可是,操作系统的调度机制和其他回调函数都有可能延迟执行Timers queue中的回调函数。

事实上,poll阶段决定着什么时候执行timers queue中的回调。

如下代码所示:

const fs = require('fs');

function someAsyncOperation(callback) {
  // Assume this takes 95ms to complete
  fs.readFile('/path/to/file', callback);
}

const timeoutScheduled = Date.now();

setTimeout(() => {
  const delay = Date.now() - timeoutScheduled;

  console.log(`${delay}ms have passed since I was scheduled`);
}, 100);

// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() => {
  const startCallback = Date.now();

  // do something that will take 10ms...
  while (Date.now() - startCallback < 10) {
    // do nothing
  }
});

fs.readFile('/path/to/file', callback);会使EventLoop进入poll阶段,由于fs.readFile()没有执行结束,此时poll queue中的回调函数为空,因此在没有意外的情况下等待一段时间等到timers阶段规定的时间阈值100ms去执行timers阶段对应的回调函数。但是在95ms的时候。fs.readFile()执行完毕,文件读取结束,接下来会将fs.readFile()对应的回调函数添加进poll queue并执行10ms。当poll queue中fs.readFile()对应的回到函数执行结束以后,EventLoop会查看在poll queue中是否有其他的回调函数,目前查看暂无,于是EventLoop将进入timers queue中按照队列的弹出顺序执行对应的回调函数。在本例中,setTimeout()对应的回调函数将会在105ms后执行。

pending callbacks(回调待处理阶段)

这个阶段执行操作系统的一些操作,例如TCP errors。例如,如果 TCP 套接字在尝试连接时收到 ECONNREFUSED,则某些 *nix 系统会将该错误挂起在pending callback queue中排队执行。

poll(轮询阶段)

轮询阶段有两个主要的职能:

  • 计算I/O操作应该阻塞和轮询的时间
  • 在poll queue中处理事件。

当EventLoop进入poll 阶段并且当前timers queue为空,将会:

  • 如果poll queue不为空,EventLoop将会一直执行poll queue中的回调函数,直到poll queue为空或者到了NodeJS的硬限制。
  • 如果poll queue为空,将会:
    • 如果调用了setImmediate()函数,EventLoop会结束poll阶段的执行,进入check阶段执行setImmediate()对应的回调函数。
    • 如果没有调用setImmediate()函数,EventLoop会停留在poll阶段,当poll queue中添加了回调函数的时候会被立即执行。

一旦poll queue为空,EventLoop会立即检查timers queue中是否有回调函数,如果有将会立刻从poll阶段返回timers阶段去执行timers queue中的回到函数。

check(检测阶段)

这个阶段允许用户立即执行回调函数(在poll queue为空的情况)。setImmediate() 实际上是一个特殊的计时器,它在事件循环的一个单独阶段运行。 它使用 libuv API 来安排在轮询阶段完成后执行的回调。

通常,随着代码的执行,EventLoop最终会进入poll阶段,在那里它将等待传入的连接、请求等。但是,如果使用 setImmediate() 安排了回调并且poll阶段变为空闲,则EventLoop将结束并进入check阶段,而不是等待轮询事件。

close callbacks(关闭回调阶段)

如果套接字或句柄突然关闭(例如 socket.destroy()),则将在此阶段发出 ‘close’ 事件。 否则它将通过 process.nextTick() 发出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/148288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vmware安装MacOS以及flutter遇到的问题

安装过程&#xff1a;参考下面的文章 链接&#xff1a; 虚拟机VMware安装苹果系统macOS&#xff0c;超级详细教程&#xff0c;附文件下载&#xff0c;真教程&#xff01;&#xff01; 无限重启情况&#xff1a; &#xff08;二&#xff09; 配置虚拟机找到你的虚拟机安装文件…

查询站点真实IP地址,绕过CDN

一.如何判断站点是否使用了CDN&#xff1f; 使用其他省市的电脑进行ping看返回的IP地址是否相同通过第三方网站查询 站长工具 3.nslookup命令 二. 如何绕过CDN获取真实IP 子域名查询&#xff0c;因为很多站点只对主域名进行了CDN加速网站邮件头信息微步在线DNS查询

[PyTorch][chapter 63][强化学习-QLearning]

前言&#xff1a; 这里结合走迷宫的例子,重点学习一下QLearning迭代更新算法 0,1,2,3,4 是房间&#xff0c;之间绿色的是代表可以走过去。 5为出口 可以用下图表示 目录&#xff1a; 策略评估 策略改进 迭代算法 走迷宫实现Python 一 策略评估 强化学习最终是为了…

算法通关村——数组中第K大的数字

数组中第K大的数字 1、题目描述 ​ LeetCode215. 数组中的第K个最大元素。给定整数数组nums和整数k&#xff0c;请返回数组中第k个最大的元素。请注意&#xff0c;你需要找的是数组排序后的第k个最大的元素&#xff0c;而不是第k个不同的元素。 示例1&#xff1a; 输入&#…

LLM prompt提示工程调试方法经验技巧汇总

现在接到一个LLM模型任务&#xff0c;第一反应就是能不能通过精调prompt来实现&#xff0c;因为使用prompt不需要训练模型&#xff0c;只需输入指令就可以实现和LLM的交互。按照以往经验&#xff0c;不同的prompt对模型输出影响非常大&#xff0c;如果能构造一个好的prompt&…

【23真题】厉害,这套竟有150分满分!

今天分享的是23年中国海洋大学946的信号与系统试题及解析。 本套试卷难度分析&#xff1a;22年中国海洋大学946考研真题&#xff0c;我也发布过&#xff0c;若有需要&#xff0c;戳这里自取!平均分为109-120分&#xff0c;最高分为150分满分&#xff01;本套试题内容难度中等&…

【vue】 实现 自定义 Calendar 日历

图例&#xff1a;自定义日历 一、标签自定义处理 <div class"date-box"><el-calendar v-model"state.currDate" ref"calendar"><template #header"{ date }"><div class"date-head flex"><div …

Golang获取月份的第一天和最后一天

package mainimport ("fmt""strconv""strings""time" )func main() {month : "2023-11"result : GetMonthStartAndEnd(month)fmt.Println(result["start"] " - " result["end"]) }// 获取月…

图形化探索:快速改造单实例为双主、MGR、读写分离等架

单机GreatSQL/MySQL调整架构为多副本复制的好处有哪些&#xff1f;为什么要调整&#xff1f; 性能优化&#xff1a;如果单个GreatSQL服务器的处理能力达到瓶颈&#xff0c;可能需要通过主从复制、双主复制或MGR&#xff0c;以及其他高可用方案等来提高整体性能。通过将读请求分…

zabbix的服务器端 server端安装部署

zabbix的服务器端 server 主机iplocalhost&#xff08;centos 7&#xff09;192.168.10.128 zabbix官网部署教程 但是不全&#xff0c;建议搭配这篇文章一起看 zabbixAgent部署 安装mysql 所有配置信息和Zabbix收集到的数据都被存储在数据库中。 下载对应的yum源 yum ins…

【Linux】非堵塞轮询

堵塞轮询&#xff1a; 堵塞轮询是我们最简单的一种等待方式也是最常应用的等待方式。 但是&#xff0c;一旦阻塞等待也就意味着我们当前在进行等待的时候&#xff0c;父进程什么都干不了。 非堵塞轮询&#xff1a; 其中非阻塞等待&#xff0c;是等待的一种模式&#xff0c; 在…

如何使用Imagewheel+内网穿透搭建私人图床实现公网访问

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

【淘宝API】商品详情+搜索商品列表接口

淘宝商品详情API接口可以使用淘宝开放平台提供的SDK或API来获取。这些接口可以用于获取商品的详细信息&#xff0c;如标题、价格、描述、图片等。 以下是使用淘宝开放平台API获取商品详情的步骤&#xff1a; 注册淘宝开放平台账号&#xff0c;并创建应用&#xff0c;获取应用…

Sentinel 流控规则

Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 SpringbootDubboNacos 集成 Sentinel&…

下一代VPN工具:体验TailScale的简便和高效

目录 一、概要VPN 是什么&#xff1f;TailScale 是什么 二、使用1、注册2、下载安装3、 Windows4、Linux5、 Android6、测试 三、Nginx整合Tailscale做端口转发 一、概要 VPN 是什么&#xff1f; 看到 VPN 第一反应应该是翻墙&#xff0c;但 VPN 最初应该也是最普遍的用途应该…

重生奇迹mu圣导师加点

重生奇迹mu圣导师加点&#xff1a;要攻击高可以加力量&#xff0c;平衡系建议加点力量600~800&#xff0c;智力200~400&#xff0c;敏够装备要求&#xff0c;统帅1000&#xff0c;其余加体力。 圣导师靠加力量培养高攻圣导师不现实&#xff0c;建议玩家练魔&#xff0c;低级圣…

win10关闭讲述人、粘滞键功能的快捷键启动

简单记录下在win10关闭讲述人、粘滞键快速启动的快捷键&#xff0c;这两个功能对正常人没什么用。误触发很烦。 禁用讲述人 按windows键&#xff0c;输入“轻松使用设置”&#xff0c;点“讲述人”&#xff0c;如下图取消讲述人开关和快捷键的勾选。 禁用粘滞键 按windows…

算法笔记-散列

算法笔记-散列 hash算法的思想整数出现的个数字符串出现个数整数是否出现整数出现的个数2字符是否出现字符串出现的个数2-sum-hash字符串出现的次数集合求交集合求并集合求差hash算法的思想 散列方法的主要思想是根据结点的关键码值来确定其存储地址 以关键码值K为自变量,通过…

电子学会C/C++编程等级考试2021年03月(一级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:药房管理 随着信息技术的蓬勃发展,医疗信息化已经成为医院建设中必不可少的一部分。计算机可以很好地辅助医院管理医生信息、病人信息、药品信息等海量数据,使工作人员能够从这些机械的工作中解放出来,将更多精力投入真正的医…

【Java 进阶篇】JQuery 案例:优雅的隔行换色

在前端的设计中&#xff0c;页面的美观性是至关重要的。而其中一个简单而实用的设计技巧就是隔行换色。通过巧妙地使用 JQuery&#xff0c;我们可以轻松地实现这一效果&#xff0c;为网页增添一份优雅。本篇博客将详细解析 JQuery 隔行换色的实现原理和应用场景&#xff0c;让我…