互联网会发生
使用 域名访问 Web服务器
浏览器发现网址不是 IP 地址,会发起域名解析动作。通过访问一系列的域名解析的过程,试图把域名翻译成 TCP/IP 协议的 IP 地址。
域名解析过程:
- 浏览器缓存
- 操作系统缓存
- hosts 文件可以覆写
- 访问域名解析服务器
使用 IP 地址访问 Web服务器
HTTP 协议是运行在 TCP/IP 基础上的,依靠 TCP/IP 协议来实现数据的可靠传输。
所以浏览器要用 HTTP 协议收发数据,首先要做的就是建立 TCP 连接。
简要叙述一下一次最简单的浏览器 HTTP 请求过程:
- 浏览器从地址栏的输入中获得服务器的 IP 地址和端口号;
- 浏览器用 TCP 的三次握手与服务器建立连接;
- 浏览器向服务器发送拼好的报文;
- 服务器收到报文后处理请求,同样拼好报文再发给浏览器;
- 浏览器解析报文,渲染输出页面;
浏览器的工作
- 不稳定
如果有一个页面卡死可能会导致整个浏览器
- 控制除标签页外的用户界面
- 包括地址,书签,后退,前进按钮等
- 以及负责与浏览器其他进程负责协调工作
缓存进程
网络进程
- 负责发起网络请求
GPU 进程
- 整个浏览器页面渲染
插件进程
- 整个网页所使用到的插件,如 flash
浏览器输入地址时
浏览器进程 UI 线程会捕捉输入内容,
如果输入是网线,则 UI 线程启动一个网络线程请求 DNS 进行域名解析,连接服务器获取数据
如果输入是关键词,于是会使用默认配置的搜索引擎来查询
网络线程获取到数据之后的工作
- 通过 SafeBrowsing 检查网站是否为恶意站点
- 如果是浏览器提示警告页面
- 告诉安全问题
- 并会阻止访问
- 如果是浏览器提示警告页面
- 通过检查后,网络线程会通知 UI线程
- UI 线程会创建渲染器进程来渲染页面
- 浏览器进程通过 IPC 管道将数据传给渲染器进程
- 正式进入渲染流程
- 渲染器进线把 HTML / CSS / JS / 图片 等资源渲染为用户可以交互的 WEB 页面
- 将 HTML 解析,得到 DOM Tree
- 构造 DOM 数据结构
- Tokeniser 标记化,把 HTML 解析成多个标记
- DOM 树构造,通过标记生成
- 当遇到脚本,会停止 HTML 解析流程
- DOM 生成 document 对象
- 构造 DOM 数据结构
- 解析CSS
- 样式计算
- 解析样式
- 生成 Layout Tree 布局
- DOM Tree 与 Layout Tree 不一定一一对应
display : none
不会出现在 Layout Tree- 伪类不会出现在 DOM Tree
- DOM Tree 与 Layout Tree 不一定一一对应
- 遍历 Layout Tree 创建绘制记录表 Paint
- 代表绘制的顺序
- 把信息传递给 合成器线程
- 栅格线程
- 进行栅格化,把信息转化成像素点
- 生成合成器帧Frame
- 栅格线程
- 将 HTML 解析,得到 DOM Tree
- 通过 IPC 把合成器帧交给浏览器进程
- 再由浏览器进程把合成器帧传送到 GPU
- GPU 渲染展示到屏幕上
- 渲染器进线把 HTML / CSS / JS / 图片 等资源渲染为用户可以交互的 WEB 页面
当页面发生变化,都会生成一个新的合成器帧 传给GPU进行渲染
浏览器的渲染工作总结
- 主线程
- 将 HTML 解析构造 DOM 树
- 进行样式计算 Style
- 由 DOM 和 style 生成 Layout Tree
- 遍历 Layout Tree 生成绘制顺序表 Paint
- 遍历 Layout Tree 生成图层 Layer
- 合成器线程把图层分为更小的图块 Tiles
- 栅格线程
- 栅格化 raster
- 发送 draw quads 图块信息
- 合成器线程生成合成帧 Frame
- IPC 传给浏览器进程
-
重排
重绘
如改变元素的背景颜色,会除 布局 Layout 和 生成图层 Layer 之外的操作
引出动画问题
JavaScript 也会在主线程中运行,会与重排和重绘抢占执行时间的问题。
一个不断导致重排重绘的动画,浏览器需要在每一帧都运行样式计算布局中和绘制的操作。而在以每秒 60 帧的刷新才不肢让用户感觉而在卡顿,如果在运行动画时还有大量的 JS 任务需要进行。
在一帧的时间内布局和绘制结束后,还有剩余时间 JS 就会拿到主线程的使用权。如果 JS 的执行时间过长,会导致在下一帧动画没有按时渲染,就会出现动画的卡顿。优化手段
requestAnimationFrame()
会在每一帧被调用,把 JS 任务分成一些更小的任务块(分到每一帧),在每一帧时间用完前暂停 JS 执行,归还主线程。
React Fiber 用了这 API 做了很多优化
- CSS 的 Transform
栅格化的整个流程是不占用主线程,只在合成器线程和栅格化线程中运行,无需与 JS 抢夺主线程。
通过 CSS Transform 属性实现动画不会经过布局和绘制,而是直接运行在合成器线程和栅格线程中,不会受主线程中 JS 执行的影响。更重要是 Transform 实现的动画由于不需要经过布局绘制样式计算等操作,节省很多运算。