每年都在写面试题。。写多了知识点也就都记住了。。
1.进程和线程(我在22年面试的时候被问到过)
进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)
线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行,一个进程中可以有多个线程)
2.浏览器是多进程的
最新的Chrome浏览器包括:1个浏览器主进程
,1个GPU进程
,1个网络进程
,多个渲染进程(因为 大部分tab页都有一个单独的渲染进程)
和多个插件进程
-
浏览器主进程
- 浏览器主进程,控制浏览器工具栏(如前进后退按钮,地址栏,书签等)
- 处理网络请求
- 文件访问
- 标签页的新建或关闭等
-
GPU进程
- 负责整个浏览器界面的渲染
-
网络进程
- 负责发起和接受网络请求
-
渲染进程
很重要,包括页面渲染,脚本执行,事件处理等- 核心任务是将HTML、CSS、JS转为用户可以与之交互的网页
- 排版引擎Blink和JS引擎V8都是运行在该进程中
-
插件进程
- 主要是负责插件的运行,因为插件可能崩溃,所以需要通过插件进程来隔离,以保证插件崩溃也不会对浏览器和页面造成影响
3.渲染进程
渲染进程是需要着重学习的
其中包括多个进程GUI渲染线程
,JS引擎线程
,计时器线程
,异步http请求线程
和事件触发线程
-
GUI渲染线程
负责渲染页面,解析html和css、构建DOM树、CSSOM树、渲染树和绘制页面,重绘重排也是在该线程中进行
-
JS引擎线程
一个tab页中只有一个JS引擎线程(单线程),负责解析和执行JS,GUI渲染线程与JS引擎线程是互斥的,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行,所以JS引擎线程执行过长会阻碍页面渲染。
-
计时器线程
主要控制 setInterval和 setTimeout,用来计时,计时完毕后,则把定时器的处理函数推进事件队列中,等待 JS 引擎线程
-
事件触发线程
属于浏览器内核线程,主要用于控制事件,例如鼠标、键盘等,当事件被触发时,就会把事件的处理函数推进事件队列,等待 JS 引擎线程执行
-
异步http请求线程
XMLHttpRequest连接后浏览器开的一个线程,比如请求有回调函数,异步线程就会将回调函数加入事件队列,等待JS引擎空闲执行
这里我也提出了自己的一个疑问,为什么有网络进程了,渲染进程还要单独开异步请求线程?
- 异步 HTTP 请求通常是由 JavaScript 代码触发的,而 JavaScript 的执行环境是在渲染引擎进程中。
- 将异步请求与渲染引擎放在同一个进程中可以更有效地处理请求和响应,减少了进程间通信的开销
我的总结:
3、4、5其实就是异步程序,包括定时器、事件以及异步请求,它们是有自己的处理线程的,时间到了,事件结束,请求结束之后的回调函数会被推进JS引擎队列,等待执行。
在不了解线程这个概念之前,我一直都觉得异步难以理解!现在知道了js以及异步分别属于各自的线程,这样就清晰多了!
4.浏览器进程小结
当我们打开一个浏览器时,可以看到,任务管理器中出现了两个进程(主控进程和渲染进程),大体流程如下:
-
主控进程收到用户请求,首先获取页面内容(譬如通过网络下载资源),随后通过RenderHost接口传递给渲染进程
-
渲染进程的Renderer接口接收到消息,简单解释后,交给渲染线程,开始渲染
- 渲染进程收到请求,加载网页并渲染网页,这其中可能需要主控进程去获取资源和GPU进程来协助渲染
- JS线程也有可能会操作DOM(可能造成回流并重绘)
- 最后渲染进程将结果传递给主控进程,主控进程收到结果并将结果绘制出来
5.Web Worker 与 Shared Worker
1.web worker
我了解到的就是初始化一个线程,与js线程可以同时运行,将需要大量密集计算的js程序交给worker处理,最后将处理的结果返回给主线程。当然,虽然Worker线程是在浏览器中被唤起的,但是它与当前页面窗口运行在不同的全局上下文中。我们常用的顶层对象window
以及parent
对象在Worker线程上下文中是不存在的,这里面运行的js也不可以操作DOM
,所以document
对象也不存在,location
和navigator
对象可以以可读方式访问。除此之外,绝大多数Window对象上的方法和属性,都能被共享到Worker上下文WorkerGlobalScope 中。同样,Worker 线程上下文也存在一个顶级对象 self
todo:后续这一块我去找几个例子吧,先跳过了
2.shared worker
todo:后续这一块我去找几个例子吧,先跳过了
简单梳理下浏览器渲染流程
浏览器内核(也就是渲染进程)拿到内容后,渲染大概可以划分为以下几个步骤:
- 解析html建立dom树
- 解析css构建render树(将css代码解析成树形的数据结构,结合DOM合成render树)
- 布局render树(Layout/reflow),负责各元素尺寸、位置计算
- 绘制render树(paint),绘制页面像素信息
- 浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上
渲染完毕后就是load
事件了,之后就是自己的JS逻辑处理了
理解了之后,下面这张图也是轻轻松松就看懂了
补充知识点:
-
load事件与DOMContentLoaded事件的先后
- 略过几个后面再说吧
-
占位符
-
普通图层和复合图层
新的概念,还是挺感兴趣的
我读过后理解的就是在新的图层上绘制,不改变默认复合图层,避免回流和重绘,这样就可以提升渲染效率
渲染步骤中提到了
composite
概念可以简单理解,浏览器的渲染的图层一般包含两大类:普通图层和
复合图层
我们经常提到的普通文档流就是一个复合图层(这里称为默认复合层),虽然absolute布局脱离文档流,但是仍然属于默认复合层。
所以我们可以通过
硬件加速的方式
声明一个新的复合图层
,也就是所谓的GPU加速
常用的调起方式:
translate3d
、translateZ
<video><iframe><canvas><webgl>
等元素
作用?
-
一般一个元素开启硬件加速后会变成复合图层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能
-
但是尽量不要大量使用复合图层,否则由于资源消耗过度,页面反而会变的更卡
硬件加速时请使用index
新内容需要慢慢理解,后面再说吧
总结
到这里,关于浏览器进程和线程我不熟悉的知识点,大概都梳理了一遍,在书写过程中,我会联想到一些小的知识点,待补充,比如,什么时候使用translated比较合适,float和absolute的区别是什么,是否能从更底层的维度去探索这些css属性设计规则等