如题等同于网页从输入网址到渲染成功的过程,我的理解分为两部分。
一.页面内容获取
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属性,更大程度上影响分层结果。
示例:
在哪里找到:
chrome为例,F12后点击工具栏最后的三个点,找到图层就能看到。
图片左侧为分层数量,右侧为分层效果。
从图中可以看到分为了6层。
我通过改变will-change属性后,将input单独分层。
分层效果:
网上说是当你页面渲染优化不明显的时候,就可以去使用这玩意去处理(我是没用到过)
5.绘制
分层结束后就会到绘制阶段也是主线程处理的最后一个阶段 主线程会对每层单独产生绘制指令集,用于描述这层页面内容如何绘制。 举例:
可能有点类似于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渣滓)