搞懂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,推敲一下就 ...
随机推荐
- 【Redis】模糊查询
Redis模糊查询 1.支持的通配符*.?.[] 2.通配符* a.单个 * 模式 # 查询所有的key keys * b.双 * 模式,匹配任意多个字符 # key中含有rich的key keys ...
- 【原创】从Ubuntu-base构建ubuntu rootfs系统(以x86_64和arm为例)
版权声明:本文为本文为博主原创文章,转载请注明出处,博客地址:https://www.cnblogs.com/wsg1100/.如有错误,欢迎指正. 目录 1.介绍 2.目的 2.准备宿主系统 2.1 ...
- MyBatis(RowBounds)分页了解内容
RowBounds 不在使用SQL实现分页 1.接口 List<User> getUserByRowBounds(); 2.mapper.xml <select id="g ...
- 【Spring】@RequestBody的实现原理
@RequestBody注解可以用于POST请求接收请求体中的参数,使用方式如下: @Controller public class IndexController { @PostMapping(va ...
- Python爬虫实战之提高CSDN访问量
python爬虫之建立代理池(一)_CodingInCV的博客-CSDN博客 python爬虫之建立代理池(二)_CodingInCV的博客-CSDN博客 前面2篇分别介绍了从2个免费代理网站爬取免费 ...
- 20.1K Star!Notion的开源替代方案:AFFiNE
Notion这款笔记软件相信很多开发者都比较熟悉了,很多读者,包括我自己都用它来记录和管理自己的笔记.今天给大家推荐一个最近比较火的开源替代方案:AFFiNE.目前该开源项目已经斩获20.1K Sta ...
- C# LinearGradientBrush使用报错
今天在学习C#时使用 LinearGradientBrush 属性发生了如上错误,发现引用其时并没有提示 在添加了此命名空间后恢复正常
- HTML超文本标记语言1
一.简介-HTML 1.什么是HTML?? 首先,HTML是WWW的描述语言,由Tim Berners-lee提出. HTML是用于描述网页的一种语言 html是指超文本标记语言(HyperText ...
- 调研capacitor兼容openharmony平台可行性
团队可能需要对开源的 capacitor 跨平台框架进行扩展,以生产支持 OpenHarmony 平台的应用,在此调研可行性.实现路径和预期工作量. 可行性分析 在验证 capacitor 是否可以将 ...
- 群晖DS218+部署PostgreSQL(docker)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 起因是懒 最近在开发中要用到PostgreSQL数据库 ...