浏览器的工作原理
介绍
当今主流的浏览器有很多,比如 chrome、firefox、safari、opera,edge,其中 chrome 和 edge 使用的是 Blink 内核,而 firefox 使用的是 Gecko 内核,而 safari 使用的是 Webkit 内核。其中 Blink 内核是根据 Webkit 内核演化而来,而如今的谷歌也得益于 webkit 内核的开源。接下来我们以 chrome 浏览器为例来深入的讲解其工作原理。
chrome
chrome 浏览器是一款多进程浏览器,但是在早期的时候,chrome 浏览器是单进程的,这意味着,所有的 tab 标签页将共用一个进程,那么假如其中一个标签页停止运行了,很有可能整个进程都会崩溃,这是很难接受的。另外,所有的 tab 标签页共用一个进程,这对于 js 来说就可以获取到浏览器内部的所有数据,这是很不安全的。
因此,之后,chrome 进行了一系列的操作,将单进程浏览器演变成多进程的浏览器。
chromeium 内核组成
- 浏览器进程:负责控制 chrome 浏览器除标签页外的用户界面。
- GPU 进程:负责整个浏览器界面的渲染。
- 插件进程:用于控制网站使用的所有插件。
- 网络进程:负责接收和发起网络请求。
- 渲染进程:用来显示 tab 标签页中的所有内容,浏览器默认默认情况下会为每个标签页创建一个进程。
- 缓存进程:处理浏览器的缓存。
在网址栏输入网址会发生什么?
当在浏览器的网址栏输入内容,浏览器的 UI 线程会捕捉你输入的内容,如果是一串网址,则 UI 线程会启动一个网络线程来请求 DNS 域名解析服务器。如果是内容,则会使用内置的搜索引擎类查询。
浏览器请求到内容后会发生到什么?
-
网络线程请求到数据,会通过 SafeBrowsing 来检测站点数据是否安全,如果不完全会弹出警告,但是你也可以强制访问。
-
当校验通过,网络线程会告知 UI 线程,UI 线程会创建一个渲染器来渲染页面。
-
渲染器进程的主线程对 HTML、CSS、JS 等资源进行解析。
-
首先解析 HTML,构成 DOM 树,DOM 就是文档对象模型。
-
HTML 当中通常包括图片/css 文件等资源,这些资源一般从网络当中,缓存当中读取。但是,当解析遇到
<script>标签的时候,会停止进行 HTML 的解析,而是去执行 JS,因为浏览器不知道 JS 脚本是否会对 DOM 进行改动,所以,需要等待 JS 脚本执行完毕后,再继续解析 HTML。所以我们一般会吧<script>标签放到合适的位置,挥着给<script>标签添加上defer,async属性来异步加载 JS 了。解析 CSS
和解析 HTML 类似,解析 CSS 也是一样,将 css 文件解析成样式树。
layout 布局
将 HTML 和 CSS 都解析成功之后,主线程会遍历 DOM 树和计算好的样式树来生成 layout tree。layout tree 上的每一个节点都记录了对应的 x,y 坐标以及边框尺寸。
注意:DOM tree 和 layout tree 是两个不同的 tree,他们之间并不是一一对应的,比如在 DOM tree 当中
display:none的节点不会在 layout tree 当中出现,而在 before 伪类元素中,添加了context属性的值不会出现在 DOM tree 当中,但是会出现在 layout tree 当中。绘制页面
当 layout tree 生成完之后,就来到了绘制页面的过程。首先遍历 layout tree 生成绘制顺序表和 layer tree。然后将 layer tree 与绘制顺序表一起发送给合成器线程,合成器线程将 layer tree 和顺序表分解成图块传给栅格线程。栅格线程对其进行栅格化操作,栅格化完成之后,将栅格化后的
draw quads图块信息传递回合成器线程。根据这些信息,合成器线程合成一个合成器帧。然后通过 IPC 管道传递给浏览器进程,之后浏览器进程传送给渲染器进程。重排
当我们修改了一个元素的大小、位置、属性的时候,会重新进行样式计算,布局、绘制、以及后面的所有流程。
重绘
当我们更改一个元素的颜色属性时,不会重新触发布局,但还是会触发样式计算和绘制,这就是重绘。
重排、重绘与 JS
重排和重绘都会占用主线程的资源,而 javascript 也是在主线程当中运行的,这样就会出现主线程的抢占。
如果有一个不断进行重排与重绘的动画,在一个时间帧当中,当动画执行完,剩下的时间才会执行 JS,但是当时间帧执行完毕,JS 没有执行完,就会抢占主线程,这样动画就无法执行,动画在页面上就会出现卡顿的现象。
优化方法
- 使用
requestAnimationFrame来进行优化,这个 API 可以将 JS 分解成更小的任务块,分到每一个时间帧当中这样就不会出现 JS 因为执行时间过长而抢占主线程的情况。 - 在栅格化线程和合成器线程中是不会和 JS 抢占主线程的,而 CSS 当中的
transfrom属性实现的动画不会在主线程当中运行,而是在合成器线程和栅格化线程当中运行。更重要的是,经过transfrom来实现的动画不需要进行布局与绘制,样式计算等操作,节省了大量的时间。
- 使用