搞懂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,推敲一下就 ...
随机推荐
- MD文本编辑工具推荐-matktext
最开始是用vscode编辑markdown文档,左边写右边看效果的实时渲染模式,对于markdown编辑来说是多余的,多是文字类的内容,配以插图,复杂表格和脑图则更少.之后接触到Typora,所打即所 ...
- 现代C++(Modern C++)基本用法实践:三、移动语义
概述 移动 移动(move)语义C++引入了一种新的内存优化,以避免不必要的拷贝.在构造或者赋值的时候,如果实参是右值(或者左值由std::move转换成右值),便会匹配移动语义的函数调用如下述举例的 ...
- 智能制造之路—从0开始打造一套轻量级MOM平台之仓库管理(WMS)
一.前言 讲仓库管理(WMS)之前,我们先来谈一谈ERP.前一篇文章,大家可以看出,我在做MOM平台规划的时候并没有提到任何ERP的信息,并不是被忽略掉了:而是对于制造企业来说,ERP是重中之重. M ...
- #Powerbi 1分钟学会利用AI,为powerbi报表进行高端颜色设计
在BI报表的设计中,配色方案往往成为一大难题,一组切合主题.搭配合理的颜色设计往往能为我们的报表,加分不少. 今天,就介绍一个AI配色的网站,利用AI为pbi报表进行配色设计. 一:网站网址 http ...
- 解决AccessDatabaseEngine.exe 32位64位安装失败问题
cmd下执行 你的路径\AccessDatabaseEngine.exe /quiet 转载于:https://www.cnblogs.com/64mb/p/10844676.html
- .Net Web API 004 Controller获取对象列表,传入数据以及对象
1.返回UserEntityList 这个服务接口的目的是分为用户列表,代码如下所示. /// <summary> /// 得到用户列表 /// </summary> /// ...
- 新一代开源流数据湖平台Apache Paimon入门实操-下
@ 目录 实战 写表 插入和覆盖数据 更新数据 删除数据 Merge Into 查询表 批量查询 时间旅行 批量增量查询 流式查询 时间旅行 ConsumerID 查询优化 系统表 表指定系统表 分区 ...
- 从浅入深了解.NET Core MVC 2.x全面教程【第二章】
二.Logging 1.诊断中间件 命名空间:Microsoft.AspNetCore.Diagnostics 报告信息并处理异常 2.诊断中间件 UseDeveloperExceptionPage: ...
- 《Redis核心技术与实战》学习笔记总结目录
1 Redis学习路径 去年我学习了极客时间的<Redis核心技术与实战>课程,在这门课程的学习中,我经常看到一位课代表的发言,他就是Kaito,他总结了一份Redis学习路径脑图(建议收 ...
- 《SQL与数据库基础》21. 分库分表(一)
目录 分库分表(一) 拆分策略 垂直拆分 垂直分库 垂直分表 水平拆分 水平分库 水平分表 技术实现 MyCat概述 概念介绍 环境准备 目录介绍 MyCat入门 配置 分片配置(schema.xml ...