15 | 消息队列和事件循环:页面是怎么“活”起来的?
15 | 消息队列和事件循环:页面是怎么“活”起来的?
讲述:李兵
时长12:56大小11.81M
使用单线程处理安排好的任务
在线程运行过程中处理新任务
处理其他线程发送过来的任务
处理其他进程发送过来的任务
消息队列中的任务类型
如何安全退出
页面使用单线程的缺点
实践:浏览器页面是如何运行的
总结
思考时间
赞 61
提建议
精选留言(108)
- 肥嘟嘟左卫门2019-09-09老师,我感觉最近学起来很迷茫。我本身是非计算机专业的,转行前端将近一年,也能照搬代码去干活,但是总感觉很多东西不通,整个就是一个闭塞的状态,于是我把今年的目标定为恶补计算机基础知识,然后我就找计算机网络方面的知识,浏览器方面的,也包括您的这个专栏,并且也结合着极客时间另外一个关于http的专栏,感觉看的时候好像是懂了(其实我也知道也只是停留在我这个知识层面的“懂了”),会有那种原来平时工作时候他们说的那些概念是这样的意思,也会觉得曾经觉得很难得东西,一下子就通了的感觉,但是另一边我又发现一个问题就是看到现在,像之前专栏讲的我就忘了,平时打通的点也都没有太多印象。我有点迷茫了,我不知道是不是因为我实操太少了,平时遇到的问题太少,所以在学这些的时候会印象不深刻。难道我现在应该把更多的精力放在框架的使用,不停的写代码,而不是基础上吗?展开
作者回复: 首先我的观点是工作和知识体系的构建都是重要的,这两者向铺相成。 所以学习过程也是停不下来的,基础知识的学习不要间断。 工作是实践的好机会,但是在工作中你涉及到内容通常会限定在一个很窄的领域,要想通过工作拓宽自己的知识边界,那该如何突破呢? 我是这样做: 把工作中的项目看成是一个探险游戏,游戏中有你熟悉的领域,也有你不熟悉的领域,通常你所做的工作都是在你最熟悉的领域。 不过我还会做另外一件事,就是把游戏地图画出来,画地图的过程也就是全面熟悉项目架构的过程,其中可能涉及到很多你不熟悉的领域,然后你要做的事逐步拓宽这张地图! 当然人的精力是有限的,所以搭建知识架构很重要,然后再找几个领域深耕。
共 10 条评论154 - 易儿易2019-09-08宏任务是开会分配的工作内容,微任务是工作过程中被临时安排的内容,可以这么比喻吗?
作者回复: 这个比喻形象
共 3 条评论135 - 拖鞋2019-09-16老师请教个问题 用CSS3实现动画是不是不会影响主线程,和用JS实现动画会影响主线程,这个说法对么
作者回复: 是这样的,部分css3的动画效果是在合成线程上实现的,不需要主线程介入,所以省去了重拍和重绘的过程,这就大大提升了渲染效率。 JavaScript都是在在主线程上执行的,所以JavaScript的动画需要主线程的参与,所以效率会大打折扣!
80 - 阿桐2019-09-22老师,为什么说页面是单线程架构? 默认情况下每个标签页都会配套一个渲染进程,而一个渲染进程里不是有主线程、合成线程、IO线程等多个线程吗 是因为【排版引擎 blink】 和【JavaScript引擎 v8】都工作在渲染进程的主线程上并且是互斥的,基于这点说页面是单线程架构?展开
作者回复: 是的,他们都是在渲染进程的主线程上工作,所以同时只能执行一个。 比如v8除了在主线程上执行JavaScript代码之外,还会在主线程上执行垃圾回收,所以执行垃圾回收时停止主线程上的所有任务,我们把垃圾回收这个特性叫着全停顿。
43 - 052D-1312020-03-21早就了解宏任务和微任务的区别了,但这篇文章让我一下子明白了微任务的来龙去脉,有拨云见日之感。共 1 条评论40
- mfist2019-09-07微任务的本质结合消息队列和事件循环我理解:当事件循环接受到消息时候,判断是否是优先级高的任务,选择插入消息队列的位置不同,进而影响消息执行的顺序。 很期待通过js回调方式解决一次执行很长js带来的页面卡顿的问题。 今日总结 为了应对渲染进程主线程繁琐的任务(DOM解析、样式计算、布局、处理js任务、各种输入事件),引入了消息队列和事件循环系统。 从任务的复杂度逐渐增加,循序渐进的分析每种场景的处理方式。 1. 单线程处理安排好的同步任务 2. 引入事件循环接受新的任务 3. 引入消息队列处理其他进程发来的任务 4. 引入宏任务和微任务解决任务优先级的问题 5. 通过Js回调功能解决单个js任务执行时间过长的问题。展开
作者回复: 你对微任务的理解还是有些偏差的! 每个宏任务都有一个微任务列表,在宏任务的执行过程中产生微任务会被添加到改列表中,等宏任务快执行结束之后,会执行微认为列表,所以微任务依然运行在当前宏任务的执行环境中,这个特性会导致宏任务和微任务有一些本质上的区别!我们后面再介绍,你可以重点关注下。
共 12 条评论36 - 六个周2019-11-25由于是多个线程操作同一个消息队列,所以在添加任务和取出任务时还会加上一个同步锁。 请问老师,JS执行不是单线程的吗?为什么这里会说是由多个线程操作同一个队列?
作者回复: 这里提到的任务是指浏览器所以需要处理的任务! 浏览器是基于多进程+多线程架构的,所以多进程通讯(IPC)和多线程同步的问题! 因为JavaScript引擎是运行在渲染进程的主线程上的,所以我们说JavaScript是单线程执行的!
共 4 条评论30 - 鹿一君2020-06-01这是目前买的几个课里面讲的最好和最认真的共 2 条评论25
- 蚂蚁内推+v2019-12-20老师,请问浏览器的事件循环和js event loop是一回事吗?
作者回复: JavaScript没有自己循环系统,它依赖的就是浏览器的循环系统,也就是渲染进程提供的循环系统! 所以可以说是一回事
21 - L-Chris2020-05-14事件循环的本质是for循环,循环不会一直迭代导致主线程卡主吗?
作者回复: 不会,实际过程中采用系统级中断机制,也就是有事件时,线程才会被激活,没事件时,线程就会被挂起
16 - Rapheal2019-09-08老师,可以请问下:渲染进程的主线程和V8执行机主线程是同一个线程吗?一个渲染进程有几个线程,分别有啥作用?
作者回复: 主要有IO线程,用开负责和其它进程IPC通信的,然后主线程主要跑页面的! V8是在主线程上执行的,因为dom操作啥的都是在主线程上执行的。 当然还有其它很多辅助线程,比如预解析DOM的线程,垃圾回收也有一些辅助线程。
13 - 趁你还年轻2332020-06-13宏任务是开会时PM定好的需求,微任务是开发过程中PM新加的加急需求。 假设一场迭代会议定下来3个宏任务,在开发第2个宏任务到60%进度的时候,PM新提了一些小的微任务。执行时间可以表示为:第2个宏任务完成之后---[执行新加入的微任务]---第3个宏任务开始之前。11
- 花儿与少年2019-09-08宿主发起的任务是宏任务 如点击事件,settimeout 进消息队列;js引擎发起的任务是微任务如promise共 4 条评论9
- GY2019-09-25非常疑惑,几个问题希望能解答一下 1.我在查阅一些资料,是这么描述的,渲染进程主要有GUI渲染渲染线程,JS引擎线程,事件触发线程,定时触发器线程。而本文一直在讲主线程,那么主线程到底是什么?是独立于这几个线程吗,还是这几个线程中的某一个 2.您在回答提问中,有提到了IO线程,以及辅助线程,这些又是什么?我在网上查不到比较好的回答 3.比较好奇window.onload的是如何执行的,js引擎执行到这段代码时,不会立即执行,那么会将这段代码怎么处理,什么时候执行,当他被触发时,是作为宏任务进入消息队列还是微任务进入微任务队列,还是其他的方式? 4.我该如何理解任务,因为我在测试一个HTML文件中出现多个script标签且都包含一段setTimeout,前面的script中的setTimeout函数,有时会先于后面的script块执行,那么我应该怎么理解这个过程,他并不是按照 第一个script标签中代码编译--执行--setTimeout进入消息队列--微任务执行--第二个script标签编译--执行--setTimeout进入消息队列--微任务执行.....--从消息队列取出第1个script标签中的setTImeout执行--从消息队列取出第2个script标签中的setTImeout执行展开共 16 条评论9
- 得闲读书2019-09-07老师,所以,事件循环其实是监听执行任务的循环机制吗?而每一个执行任务都存档在消息队列里面,这些统称为宏任务,微任务是执行宏任务中遇到的异步操作吧,就是异步代码,如promise,settimeout任务。执行宏任务遇到异步任务先将其放入微任务列表,等该宏任务执行一遍后再执行该宏任务的微任务列表,我这样理解对吗?
作者回复: 第一个理解没错,事件循环系统就是在监听并执行消息队列中的任务! 第二个理解也没问题,不过promise触发的微任务,settimeout触发的是宏任务!
7 - 阿段2019-09-19每一个宏任务都有一个微任务队列?还是整个任务队列有一个微任务队列?
作者回复: 每个宏任务都有微任务队列
共 3 条评论6 - 斯塔克2021-09-11面试官:讲一下浏览器的事件循环 事件其实就是一系列的任务,比如网络进程负责调度资源加载、渲染进程负责调度DOM解析、styleSheet生成、布局计算等,但由于浏览器只有一个主线程,而且在线程运行过程中可能产生新的任务,这时候就需要一种机制,能够不断的加入任务和执行任务。这就是事件循环系统。而加入任务的地方就是消息队列 之所以叫消息队列,我们分别从消息和队列来理解。 消息:每个渲染进程都有一个IO线程用来接受其他进程(比如网络进程等)传来的消息,这些消息便是未来(这个未来可以是一个很短的瞬间,如果当前任务不多、计算量不多)要执行的任务。 队列:这是一种数据结构,任务的调度符合队列‘先进先出’的特点,先进去的任务,拥有优先执行权,后进去的任务要等前面的任务执行完成后(完成 = 当前循环宏任务 + 对应微任务 2种任务都清空)。展开4
- 朱维娜🍍2019-09-11在渲染进程里面,除了I/O线程,其他线程也会往消息队列中添加任务,是吗?
作者回复: 有啊,比如渲染过程就有合成线程,解析DOM过程中还有预解析线程,这些现场都会和主线程有交互的
3 - 阿桐2019-09-07老师,专栏中有段内容我看了几遍还是似懂非懂,您方便举个例子再给我说说吗? “比如一个典型的场景是监控 DOM 节点的变化情况(节点的插入、修改、删除等动态变化),然后根据这些变化来处理相应的业务逻辑。一个通用的设计的是,利用 JavaScript 设计一套监听接口,当变化发生时,渲染引擎同步调用这些接口,这是一个典型的观察者模式。 不过这个模式有个问题,因为 DOM 变化非常频繁,如果每次发生变化的时候,都直接调用相应的 JavaScript 接口,那么这个当前的任务执行时间会被拉长,从而导致执行效率的下降。”展开
作者回复: 这个我会在微任务那节详细分析
共 2 条评论3 - 纪颖志2022-04-29事件循环是需要一个单独的线程来控制,还是在主线程上执行的?2