搞懂Event Loop
本文关键:
- V8是单线程的
- 任务队列排队执行
- 抽出io命令抽出到evenloop线程,消息线程,区别与主线程。(同步和异步)
- 微任务和宏任务执行顺序
- 重绘和回流
- 以上流程无限循环
可以这样理解,一个人每天都要做同样的工作,天天如此,这就是循环。他每天的工作就是先收集事件,然后处理事件(或者先处理后收集,谁知道)然后每天都是这样,像极了人生。
while (eventLoop.waitForTask()) {
eventLoop.processNextTask()
}
js基于Event Loop
Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。
JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。
浏览器 js 以及 Nodejs 都是基于事件循环,就是有一个无限循环机制:JavaScript 引擎等待任务,执行任务,然后休眠,等待更多任务。
想要理解Event Loop,就要从程序的运行模式讲起。运行以后的程序叫做“进程”(process,cpu执行),一般情况下,一个进程一次只能执行一个任务。
如果有很多任务需要执行,不外乎三种解决方法。
(1)排队。因为一个进程一次只能执行一个任务,只好等前面的任务执行完了,再执行后面的任务。
(2)新建进程。使用fork命令,为每个任务新建一个进程。
(3)新建线程。因为进程太耗费资源,所以如今的程序往往允许一个进程包含多个线程,由线程去完成任务。(进程和线程的详细解释,请看阮一峰解释《进程和线程》。)
JavaScript语言,它是一种单线程语言,所有任务都在一个线程上完成,即采用上面的第一种方法。一旦遇到大量任务或者遇到一个耗时的任务,网页就会出现"假死",因为JavaScript停不下来,也就无法响应用户的行为。
JavaScript 引擎大部分时间不执行任何操作,仅在脚本/处理程序/事件激活时运行。
任务示例
- <script src="...">加载外部脚本时,任务是执行它
- 用户移动鼠标时,任务是调度 mousemove 事件并执行处理程序
- 当计划好的时间到了 setTimeout,任务是运行其回调。
- ... 等等
设置任务-引擎处理它们-然后等待更多任务(在睡眠时消耗接近零的CPU)。引擎繁忙时可能会发生任务,然后将其排入队列。
这里涉及到几个概念,执行顺序上的宏任务和微任务,渲染上的重绘和回流。
另外两个细节:
引擎执行任务时永远不会进行渲染。任务是否花费很长时间都没关系。仅在任务完成后才绘制对 DOM 的更改。
如果一项任务花费的时间太长,浏览器将无法执行其他任务,例如处理用户事件。因此,过了一会儿,它会发出“页面无响应”之类的警报,建议终止整个页面的任务。当存在大量复杂的计算或导致无限循环的编程错误时,就会发生这种情况。
宏任务和微任务:
setTimeout(() => alert("timeout")); Promise.resolve()
.then(() => alert("promise")); alert("code");
这将是什么顺序?
- code 首先显示,因为它是常规的同步调用。
- promise显示第二个,因为它.then通过微任务队列,并在当前代码之后运行。
- timeout 最后显示,因为它是一个宏任务。
为什么js是单线程?
你也许会问,JavaScript为什么是单线程,难道不能实现为多线程吗?
这跟历史有关系。JavaScript从诞生起就是单线程。原因大概是不想让浏览器变得太复杂,因为多线程需要共享资源、且有可能修改彼此的运行结果,对于一种网页脚本语言来说,这就太复杂了。后来就约定俗成,JavaScript为一种单线程语言。(Worker API可以实现多线程,但是JavaScript本身始终是单线程的。)
如果某个任务很耗时,比如涉及很多I/O(输入/输出)操作,那么线程的运行大概是下面的样子。
上图的绿色部分是程序的运行时间,红色部分是等待时间。可以看到,由于I/O操作很慢,所以这个线程的大部分运行时间都在空等I/O操作的返回结果。这种运行方式称为"同步模式"(synchronous I/O)或"堵塞模式"(blocking I/O)。
如果采用多线程,同时运行多个任务,那很可能就是下面这样。
上图表明,多线程不仅占用多倍的系统资源,也闲置多倍的资源,这显然不合理。
Event Loop就是为了解决这个问题而提出的。作者这样定义:
"Event Loop是一个程序结构,用于等待和发送消息和事件。(a programming construct that waits for and dispatches events or messages in a program.)"
简单说,就是在程序中设置两个线程:一个负责程序本身的运行,称为"主线程";另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为"消息线程")。
上图主线程的绿色部分,还是表示运行时间,而橙色部分表示空闲时间。每当遇到I/O的时候,主线程就让Event Loop线程去通知相应的I/O程序,然后接着往后运行,所以不存在红色的等待时间。等到I/O程序完成操作,Event Loop线程再把结果返回主线程。主线程就调用事先设定的回调函数,完成整个任务。
可以看到,由于多出了橙色的空闲时间,所以主线程得以运行更多的任务,这就提高了效率。这种运行方式称为"异步模式"(asynchronous I/O)或"非堵塞模式"(non-blocking mode)。
这正是JavaScript语言的运行方式。单线程模型虽然对JavaScript构成了很大的限制,但也因此使它具备了其他语言不具备的优势。如果部署得好,JavaScript程序是不会出现堵塞的,这就是为什么node.js平台可以用很少的资源,应付大流量访问的原因。
这样看,异步模式,似乎是两个线程,在原来单线程的基础上,衍生出来另一条线,即evenloop线程
总结
详细的事件循环算法(尽管与规范相比仍简化了):
1从宏任务队列中出队并运行最早的任务(例如“脚本”)。
2执行所有微任务: - 当微任务队列不为空时: - 出队并运行最旧的微任务。
3渲染更改(如果有)。
4如果宏任务队列为空,请等待直到出现宏任务。
5转到步骤1。
搞懂Event Loop的更多相关文章
- js 彻底搞懂事件循环机制 Event Loop
我们都知道javascript是单线程语言,就是因为单线程的特性,就不得不提js中的同步和异步 一.同步和异步 所谓单线程,无非就是同步队列和异步队列,js代码是自上向下执行的,在主线程中立即执行的就 ...
- 原本准备的 event loop 分享
基础介绍 Stack 栈 一种先入后出的数据结构. 两个基本操作: 推入,弹出 Queue 队列 一种先入先出的数据结构 操作: 入队,出队 两种任务: 同步任务,异步任务 同步任务: 在调用栈中等待 ...
- setTimeout和setImmediate到底谁先执行,本文让你彻底理解Event Loop
笔者以前面试的时候经常遇到写一堆setTimeout,setImmediate来问哪个先执行.本文主要就是来讲这个问题的,但是不是简单的讲讲哪个先,哪个后.笼统的知道setImmediate比setT ...
- 一张图带你搞懂Node事件循环
说一件重要的事儿:你还没关注公众号[前端印记],更多精彩内容等你探索-- 以下全文7000字,请在你思路清晰.精力充沛的时刻观看.保证你理解后很长时间忘不掉. Node事件循环 Node底层使用的语言 ...
- Javascript之Event Loop
先看段代码: console.log(1); setTimeout(function () { console.log(2); new Promise(function (resolve, rejec ...
- 理解 Node.js 的 Event loop
问题 考察如下代码,脑回路中运行并输出结果: console.log("1"); setTimeout(function setTimeout1() { console.log(& ...
- JavaScipt 中的事件循环(event loop),以及微任务 和宏任务的概念
说事件循环(event loop)之前先要搞清楚几个问题. 1. js为什么是单线程的? 试想一下,如果js不是单线程的,同时有两个方法作用dom,一个删除,一个修改,那么这时候浏览器该听谁的? ...
- [转载]JavaScript 运行机制详解:再谈Event Loop
https://app.yinxiang.com/shard/s8/sh/b72fe246-a89d-434b-85f0-a36420849b84/59bad790bdcf6b0a66b8b93d5e ...
- 我所理解的event loop
灵魂三问 JS为什么是单线程的 我们都知道,JS是单线程的语言,那为什么呢?我的理解是JS设计之初就是为了在浏览器端完成DOM操作和一些简单交互的,既然涉及到DOM操作如果是多线程就会带来复杂的同步问 ...
- 【朴灵评注】JavaScript 运行机制详解:再谈Event Loop
PS: 我先旁观下大师们的讨论,得多看书了~ 别人说的:“看了一下不觉得评注对到哪里去,只有吹毛求疵之感. 比如同步异步介绍,本来就无大错:比如node图里面的OS operation,推敲一下就 ...
随机推荐
- (内附示例源码)如何通过electron构建桌面跨平台音视频应用
近年来,视频直播.直播带货.在线教育.在线医疗等音视频领域的相关行业都非常热门,成为大众瞩目的焦点. 在不久的将来,音视频技术渗透于各行各业,无处不在.从IoT网络到个人用户的移动设备,音视频技术以不 ...
- 图像处理_ISP_坏点矫正
1 坏点介绍 图像坏点(Bad pixel) : 图像传感器上光线采集点(像素点)所形成的阵列存在工艺上的缺陷,或光信号进行转化为电信号的过程中出现错误,从而会造成图像上像素信息错误,导致图像中的像素 ...
- 如何快速又高质量的输出PDF实验报告?
摘要:本文由葡萄城技术团队于博客园原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. PDF文档的打印在很多应用场景中都会被使用到,最为常见的就是实 ...
- 2023年icpc大学生程序设计竞赛-nhr
icpc的省赛是在洛阳举办,第一次出省,还是两天,第一次离开郑州去别的城市比赛,心情更多的是激动,非常感谢老师给了这次机会,第一天20号,打完热身赛之后回寝室,和队友一起看了一下去年省赛的题,感觉还是 ...
- std::ofstream 写本地音频
最近线上 PK 偶然出现双方主播互相听不见声音的情况,在日志不能明确体现问题时,就需要抓下主播本地的音频和远端的音频来确定数据是在哪消失的 所以我们用到一个比较简单的流写出的标准库类:std::ofs ...
- Vue错误:Cannot read properties of undefined (reading '$router')
解决方案 这是由于this的指向有问题,我们只需要重新声明一下this就可以重新调用了
- tensorflow.js 多分类,机器学习区分企鹅种类
前言: 在规则编码中,我们常常会遇到需要通过多种区间判断某种物品分类.比如二手物品的定价,尽管不是新品没有 SKU 但是基本的参数是少不了.想通过成色来区分某种物品,其实主要是确定一些参数.然后根据参 ...
- 介绍vue3的钩子函数activated和deactivated使用场景
activated和deactivated是Vue3中的两个生命周期钩子函数. activated钩子函数在组件被激活时调用,通常用于恢复组件的状态或执行一些初始化操作.例如,如果一个组件被从路由中激 ...
- 关于3D-AIGC的调研与探讨
0.前言 本文是自己最近在项目上的需要做的一些调研和自己的一些看法,以分享为主. 2D AIGC(文生文.文生图.图生图)在今天大放异彩,产生了许多惊艳的效果,如ChatGPT系列.Imagen.DA ...
- AWD-PWN流量监控与抄流量反打
RE手 在AWD中比较做牢,队伍里也没pwn手,在awd出现pwn靶机比较坐牢.之前都不知道pwn靶机可以抄流量反打. 参考pwn_waf:https://github.com/i0gan/pwn_w ...