浏览器渲染页面(自用)

53 阅读7分钟

如题等同于网页从输入网址到渲染成功的过程,我的理解分为两部分。

一.页面内容获取

1 输入网址,浏览器自动补全和验证域名正确性

(aaaa 报错非域名写法) (www.baidu.com baidu.com ---> 自动补全为 www.baidu.com)

2.dns解析 域名转化为远程ip地址

找ip->浏览器缓存->系统缓存(hosts)->路由器缓存->.....>根服务器 (可延伸)

3.tcp链接 (可延伸 七层协议 udp与tcp区别什么之类一大堆知屎)

三次握手 b----->s 客户端发起链接,携带个bkey(暂且叫它客户端标识)发给服务端 b<-----s 服务端接收到这个bkey,自己也搞个skey,一同发给客户端 b----->s 客户端接收到双key,知道了你就是我第一次请求的那个服务器,但是服务端不知道,然后再把这两玩意发给服务端, 然后就tm的打通了,可以发http请求了。(贼)

4.http请求

知识点: 请求体,请求头,响应内容。params,get post区别,cookie自动设置(set cookie)请求缓存keep-alive

面试题(get post区别 延申出 get能发送请求体。。。。restful接口规范,http无状态机制怎么处理)

5.通过网络请求获取到了html字符串

四次挥手 b---->s 我(b)准备断开链接了通知一下你(s) b<----s 我(s)知道了,我也准备休息了 b<----s 我(s)没有在执行的任务了byebye b---->s 好的我(b)收到了我也byebye了 后面就交给主线程和其他线程处理了。

二.页面渲染

1.html解析

主线程(渲染)会从上至下开始解析html,遇到js代码时会先解析js,解析完成后,继续解析html和css,解析完成后,根据自身的规则生成dom树和css树。

问题1:为什么解析中遇到js会被阻塞

js代码执行过程中可能会修改dom树。

问题2:如上所述什么情况下不会阻塞html解析

1> 当解析遇到link引入外部css。 原文描述为:“如果主线程解析到 link 位置,此时外部的 CSS 文件还没有下载解析好,主线程不会等待,继续解析后续的 HTML。这是因为下载和解析 CSS 的工作是在预解析线程中进行的。这就是 CSS 不会阻塞 HTML 解析的根本原因。

2> 当遇到script标签中的defer和async属性时。 defer和async都不会阻塞html解析,async代表当js代码加载完成后才会立刻解析并阻塞html解析 defer当html解析完成才会按照他在html中的顺序执行。 使用场景 async:比如说一些广告脚本和统计脚本,不依赖其他脚本和dom元素 defer:比如说我需要实现一个搜索框自动完成功能,我就需要在搜索框dom解析完成之后加载js脚本。(我看的百度首页的有个使用defer的js)

2.样式计算

主线程会遍历得到的 DOM 树,依次为树中的每个节点计算出它最终的样式,称之为 Computed Style。

在这一过程中,很多预设值会变成绝对值,比如red会变成rgb(255,0,0);相对单位会变成绝对单位,比如em会变成px 这一步完成后会生成一个带有样式的dom树 (具体如何计算的没看过)

3.构建布局

布局阶段会依次遍历 DOM 树的每一个节点,计算每个节点的几何信息。例如节点的宽高、相对包含块的位置。

大部分时候,DOM 树和布局树并非一一对应。

比如display:none的节点没有几何信息,因此不会生成到布局树;又比如使用了伪元素选择器,虽然 DOM 树中不存在这些伪元素节点,但它们拥有几何信息,所以会生成到布局树中。还有匿名行盒、匿名块盒等等都会导致 DOM 树和布局树无法一一对应。

4.分层

布局树完成构建后,主线程就会进行分层 主线程会根据一套复杂的策略对整个布局进行分层。 分层的好处在于后期 某层改变后只会对该层进行重新渲染过程,提高效率。 已知能够影响分层的属性: transform,opacity,滚动条,css也提供了一个will-change属性,更大程度上影响分层结果。 示例: image.png 在哪里找到: chrome为例,F12后点击工具栏最后的三个点,找到图层就能看到。 图片左侧为分层数量,右侧为分层效果。 从图中可以看到分为了6层。 我通过改变will-change属性后,将input单独分层。

image.png 分层效果:

image.png

网上说是当你页面渲染优化不明显的时候,就可以去使用这玩意去处理(我是没用到过)

5.绘制

分层结束后就会到绘制阶段也是主线程处理的最后一个阶段 主线程会对每层单独产生绘制指令集,用于描述这层页面内容如何绘制。 举例:

image.png 可能有点类似于webgl里面canvas绘制代码。

6.分块光栅化

从这一步开始主线程就不参与任务了,完成绘制后,主线程会把任务交给合成线程处理,合成线程会先把每个图层进行分块,将其划分成多个区域(支持多个线程进行分块),分块完成后,合成线程会把块信息交给GPU进程就行光栅化,(光栅化就是生成位图)(支持多线程光栅化),GPU会优先处理靠近视口区域的块(理解为先处理能看的面上的)。

7.画

合成线程拿到每个层、每个块的位图后,生成一个个「指引(quad)」信息。

指引会标识出每个位图应该画到屏幕的哪个位置,以及会考虑到旋转、缩放等变形。

变形发生在合成线程,与渲染主线程无关,这就是transform效率高的本质原因。

合成线程会把 quad 提交给 GPU 进程,由 GPU 进程产生系统调用,提交给 GPU 硬件,完成最终的屏幕成像。

面试题:

1.什么是 reflow?(重拍/回流)

本质就是重新计算布局树。那么就是改变了影响布局的属性都会导致回流。 那些操作会导致重新计算布局树。改变元素布局位置和大小。 比如:改变浏览器窗口大小,元素的尺寸,位置,内容发生变化(postiton:fixed,margin,width,height) 浏览器本身的部分优化机制: 当多次触发reflow时,浏览器本身会合并操作,在js代码执行完成后,才会进行reflow,so reflow操作时异步进行的。

当 JS 获取布局属性(如 offsetWidth 、 scrollTop 等)时,浏览器为了保证能获取到最新的布局信息,会立即触发 reflow 。

2.什么是repaint?(重绘)

本质上就是重新计算分层的绘制指令集,并不影响重新布局计算。

比如:改变字体颜色,背景色 透明度等等。

从渲染过程来讲只要发生reflow就会导致repaint的。

从渲染过程来讲重排reflow肯定是比repaint耗性能,所以我们在操作时,尽量避免reflow.

3.为什么transform效率高?

因为transform发生在渲染的最后画的阶段,不会引起reflow和repaint,所以效率高,换言之主线程也不会影响transform. 可以把自己页面中那些改变位置的用transform替代。(这个得多学习,css渣滓)