浏览器分为
用户界面
浏览器引擎
渲染引擎
输入网址
浏览器进程的 UI 线程会捕捉输入内容
- 如果访问的是网址,
- UI 线程会启动一个网路线程来请求 DNS 进行域名解析
- 连接服务器获取数据
- 如果输入内容是一串关键词,
- 浏览器知道你是需要搜索,就会使用默认配置的搜索引擎来查询
网络线程获取数据之后
- 通过 SafeBrowsing 来检查站点是否为恶意站点,是就会弹出恶意警告。
- 返回数据准备完毕,并且安全校验通过之后,网络线程会通知 UI 线程我已经好了
- UI 线程就会创建一个 渲染器进程 来渲染页面。
- 浏览器进程通过 IPC 管道(进程间的数据传递)将数据传递给渲染器进程
渲染流程
渲染进程接受的数据,也就是 html。渲染进程的核心任务就是把 html,css,js,image等资源渲染成用户可以交互的 web 界面
渲染器进程的主线程将 html 进行解析,构造 DOM 数据结构(程序员通过 js 与之交互的数据结构 和 API )
- html 首先经过 Tokenniser 标记化,通过词法分析将输入的 html 内容解析成多个标记。
- 根据识别后得标记进行 DOM 树构造
- 创建 Document 对象
- 然后以 document 为根节点的 DOM 树不断修改,想其中添加各种元素
- 静态资源(本地 / 网络请求)不会影响 html 的解析,不会影响 DOM 树的生成,但是当 html 解析的时候遇到 script 标签,就会停止 html 的解析流程,转而去加载并且执行 JS (如果 js 中执行了 document.write()方法就会改变当前页面的 html结构)
- html 解析完成后,就会获得一个 DOM Tree
- 主线程需要解析 css,并确定每个 DOM 节点的计算样式
layout 布局 :在知道 DOM 结构和每个节点的样式之后,需要知道每个节点在页面的坐标和占用多大的区域
- 主线程通过遍历 dom 和计算好的样式生成 Layout tree,Layout tree 上的每个节点都记录了 x,y坐标和边框尺寸。
- DOM Tree 和 Layout tree 并不是一一对应的,设置了
display:none
的节点不会出现在 Layout tree 上。而在 before 等伪类中添加了 content 值的元素会出现在 Layout tree 上。DOM Tree通过 html 解析获得,并不关心样式,而Layout tree 是根据 DOM 和 计算好的样式生成的。
绘制 :接下来需要知道以什么顺序来绘制这些节点,z-index 属性会影响节点绘制的层级关系。
- 主线程遍历 Layout tree ,创建一个绘制记录表(Paint Record),该表记录了绘制的顺序。
栅格化:将绘制信息转化为像素点,显示在屏幕上。
- 合成:将页面的各个部分分成多个图层(layer),分别对其栅格化,并在合成器线程(Compositor Thread)中单独进行合成的技术。
- 合成器线程将图层切分为许多 图块(tites),然后将每个图块发送给栅格化线程(Raster Thread)
栅格线程栅格化每个图块,并将它们存储在 GPU 内存中
- 当图块栅格化完成后,合成器线程将收集叫做为 draw quals’ 的图块信息,这些信息里记录了图块在内存中的位置和在页面的哪个位置绘制图块的信息。
- 根据这些信息,合成器线程生成了一个 合成器帧(Compositor Frame),这个合成器帧 通过 IPC 传递给浏览器进程。
浏览器进程将 合成器帧 传送给 GPU,然后 GPU 渲染展示到整个屏幕上
页面改变
- 当页面发生变化,比如滚动页面,都会生成一个新的 合成器帧 ,新的帧在传给 GPU,再次渲染到屏幕上。
- 重排:当改变一个元素的样式尺寸 位置属性时,会重新进行样式计算(Computed Style)、布局(Layout)绘制(Paint)以及后面的所有流程。
- 重绘:当改变元素的颜色属性的时候,不会重新触发布局,但还是会触发 样式计算和绘制。
重排 和 重绘 JS 都会占用主线程,如果 JS 执行时间过长,就会导致下一帧的无法按时渲染,出现页面动画的卡顿。优化手段:
requestAnimationFrame():会将主线程的任务分散到每一帧的间隔,从而不影响动画的流程
Fiber :react利用浏览器的空闲时间做优化
栅格化的整个线程是不占用主线程的。Transform 属性实现的动画不会经过 布局和 绘制,会直接运行合成器线程和栅格化线程中。
在移动端使用3d转换可以优化性能(如果设备有3d加速引擎 GPU 可以提高性能 , 2d转换是无法调用GPU,2G是靠的CPU)
避免大量重绘和重排。