浏览器相关
在浏览器里输入一行url发生了哪些事情
-
网络请求
-
构造请求
假如你输入了www.baidu.com/ 那么浏览器会构造一个请求行
// 请求方法是Get方法 // 请求路径是根路径 // 请求协议版本号是1.1 Get / HTTP1.1-
查找强缓存
如果找到强缓存就直接使用,否则往下走
-
DNS解析
通过域名找到对应的IP地址的过程就叫做DNS解析。注意:浏览器有DN解析缓存机制,当一个域名已经被解析过,下次直接使用解析过得IP不会再做DNS解析了
-
建立TCP连接
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP的链接经历了以下三个过程
-
三次握手
解释: A主机为客户端 B主机为服务端
-
A->B 我发送序号200,想要跟你建立连接,你能收到吗?作用:客户端的发送没问题
-
B->A 我收到啦,你发送的序号是200,我在此基础上给你加一,确认序号是201,我的序号是500。 作用:服务端接收没有问题,发送没有问题
-
A->B 我收到啦,你发送的序号是500,,我在此基础上给你加一,确认序号是501,我的序号需要执行加一,是201。作用:客户端接收没有问题,发送没有问题 整个流程下来可以确保客户端,服务器发送接收都没有问题
-
数据传输
发送方向接收方发送数据,如果接收方没有接受到则认为是数据包丢失,发送方会重新发送该数据包,直到接收方接收到之后给个确认消息ACK=1;另外,数据包的传输可以使用优化策略,可以把数据包拆分成一个一个的小包,接受方接收到之后可以按照顺序组合成完整的数据包
-
四次挥手
断开数据连接,客户端和服务器均可主动断开
解释:
- A->B 我发送序号200,想要跟你断开连接,你能收到吗?A主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态
- B->A 我收到啦,你发送的序号是200,我在此基础上给你加一,确认序号是201,我的序号是500。但是我不能立刻断开,因为我还有后续的报文没有执行完,等我执行完所有的保温之后再给你发一个消息B收到断开连接消息之后,进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态
- B->A 我所有的报文已经执行完了,我要跟你断开连接, 我的序号是501,你发送的序号是200,我在此基础上给你加一,确认序号是201,你能收到吗?B处于LAST_ACK (最后确认)的状态,只需等待A反馈即可
- A->B 我收到啦,你的序号是501,再次基础上我给你加一,确认序号是502,我的序号是201。B收到消息就处于CLOSED (关闭连接)的状态,而A还需要等待计时器设置的时间2MSL后,确保B一定收到消息后才能处于CLOSED (关闭连接)的状态。问: 为什么是2MSL等待时间?
思考问题
问为什么要三次握手 两次不行吗?答:只有三次才能确保客户端服务端发送和接收功能都正常
问第三次握手失败了怎么办?答:第一次握手成功后,服务器就会把这种请求放在半连接队列里面,如果第三次握手失败,服务器会重发消息给客户端,要是还收不到,再重发,直到超出系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
问:三次握手中可以携带数据吗?答:第一次第二次不能携带,第三次可以携带,因为已经建立链接了,第一次第二次分别是判断客户端发送,服务端接受,发送是否有问题,如果再此期间发送大量数据,可能会使服务器遭受到攻击,比如黑客故意在一次发送报文中携带大量数据,就会导致真实的客户端的数据不能被服务器接收,一直如此的话,此连接会被系统删除或者引起网络瘫痪。
问挥手为什么要四次?答:因为服务端可能还有排队中的报文没有执行完毕,需要等所有报文执行完毕之后再次给客户端发起断开通知
问等待时间为什么是2MSL?答:报文段在传输过程中最大的生存时间是MSL,2倍的MSL可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。并且再此时间段期间,再次调取该接口,则不能被使用,只有过了2SML之后才能被再次使用
-
发送 http请求
现在TCP建立连接之后 浏览器就可以跟服务器通信啦,浏览器发送http请求需要携带三样东西,请求行 请求头 请求体
-
请求行
第一步就已经构建好了
// 请求方法是Get方法 // 请求路径是根路径 // 请求协议版本号是1.1 Get / HTTP1.1-
请求头
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Connection: keep-alive Cookie: __yjs_duid=1_38ab900cd127edf5d094be0e7ad1ca6c1613974406843; PSTM=1614133943; BAIDUID=3E42FD376379681FD056171C116AF3A2:FG=1; BD_HOME=1; BIDUPSID=2BFFAC236F132502F30267E697F3F002; BD_UPN=123253; delPer=0; BD_CK_SAM=1; BAIDUID_BFESS=3E42FD376379681FD056171C116AF3A2:FG=1; H_PS_PSSID=33514_33344_33570_33603_33459_26350_33265; plus_lsv=44d0b5b8089055d9; plus_cv=1::m:7.94e+147; Hm_lvt_12423ecbc0e2ca965d84259063d35238=1614395292; SE_LAUNCH=5%3A26906588; H_WISE_SIDS=107318_110085_127969_131424_144966_155930_156286_156927_162898_163569_164107_164326_164456_164955_165134_165135_165329_166148_166184_166830_167069_167085_167114_167296_168388_168489_168494_168501_168542_168763_168972_169055_169063_169164_169307_169373_169699_169806_169876_170251_8000056; rsv_i=037f%2BAjO4xwfT6R%2B0q276fCmRYZpd9%2FIJUTBSDgD89kodMI%2F3h3OdLRwqsuqIjmhUBXTnwrIk2ihcNBzwsHDM3N%2Bm%2F9Llr0; Hm_lpvt_12423ecbc0e2ca965d84259063d35238=1614395308; PSINO=2; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDSVRTM=0; COOKIE_SESSION=234663_9_7_0_35_57_0_7_0_7_3_0_234668_0_3_2_1614396170_1609061618_1614396167%7C9%2321164_7_1609061616%7C4 Host: www.baidu.com Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1-
请求体
像一个接口传的参数
[{"index":1,"pageSize":50,"projectCode":"jingxiaocang","contentType":2,"resCode":"pos00007"}]-
网络响应
由三部分组成:响应行,响应头,响应体
-
响应行
Request URL: https://www.baidu.com/ Request Method: GET Status Code: 200 OK Remote Address: 110.242.68.3:443 Referrer Policy: strict-origin-when-cross-origin-
响应头
Cache-Control: no-cache Connection: keep-alive Content-Encoding: gzip Content-Type: text/html;charset=utf-8 Coremonitorno: 0 Date: Sat, 27 Feb 2021 04:47:52 GMT Server: apache Set-Cookie: H_WISE_SIDS=107318_110085_127969_131424_144966_155930_156286_156927_162898_163569_164107_164326_164456_164955_165134_165135_165329_166148_166184_166830_167069_167085_167114_167296_168388_168489_168494_168501_168542_168763_168972_169055_169063_169164_169307_169373_169699_169806_169876_170251_8000056; path=/; expires=Sun, 27-Feb-22 04:47:52 GMT; domain=.baidu.com Set-Cookie: bd_traffictrace=271247; expires=Thu, 08-Jan-1970 00:00:00 GMT Set-Cookie: rsv_i=8c5dx20kTSWp85qcyacEdS0KjAHRn7Xz2T3xBpRnALGftAoTTxv8K2BKvie6RZVYZri94ft%2FcAHAP9sZUYXRnPzuqm5sdBE; path=/; domain=.baidu.com Set-Cookie: BDSVRTM=466; path=/ Set-Cookie: eqid=deleted; path=/; domain=.baidu.com; expires=Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: __bsi=; max-age=3600; domain=m.baidu.com; path=/ Strict-Transport-Security: max-age=172800 Traceid: 161440127224717007467137245922687506809 Transfer-Encoding: chunked Vary: Accept-Encoding-
响应体
{"code":0,"data"[{"confKey":"xiangqinggonggao","confValue":""}],"msg":"调用成功"}问响应完成之后,TCP就断开连接了吗?答:不一定 ,如果请求头或响应头中包含Connection: Keep-Alive,表示建立了持久连接,这样TCP连接会一直保持,之后请求统一站点的资源会复用这个连接,如果没有该字段则断开TCP连接, 请求-响应流程结束。
总结:
-
-
页面渲染
-
构建dom树
- 标记树
根据元素解析比如
<div>hahsh</div>
- 当解析到
<状态为标记打开, - 当解析到
a-z字符时状态为标记名称状态 - 当解析到
>状态为标记名称状态结束,这时候变为数据状态 - 知道解析到
/这时候会创建一个end tag的标识 随后进入标记名称状态。
- 建树 DOM树是一个以document为根节点的多叉树,因此解析器会首先创建一个document,接着标记器会把标记的信息给到建树器,建树器接收到信息之后开始创建对应的DOM对象,创建这个对象之后会做两件事
- 将Dom对象添加到DOM树上
- 将标签闭合元素压入栈中;直到标记生成器最后传过来一个html的结束标记,结束解析
- 标记树
根据元素解析比如
-
样式计算
样式来源
- link引入
- style
- class
格式化样式
浏览器是无法直接识别css样式的,因此渲染引擎收到css文本时,首先生成一个样式对象 styleSheet,可以通过document.styleSheets查看该结构 ![]
!
标准化样式
根据css里面的 white->#ffffff black->#000000 blod->700 等
计算每个元素的样式
规则:继承+层叠 继承父元素样式,叠加自己的样式,最终组合出现的样式
-
生成布局树
有DOM,有样式,但是还要确定元素在浏览器里面的位置,所以需要生成布局树。
-
遍历DOM树里面的节点,添加到布局树里面
-
给每个元素确定位置 注意:布局树只有包含可见的元素,head和display:none不存在与布局树里
-
构建图层树
因为会有z-index position scroll 等,所以需要构建一个图层树,
-
显示合成
- 设置定位 position不为static的定位 并且设置了z-index属性
- 设置滤镜 filter不为none时
- 设置伸缩 transfrom不为none时
- 设置opticy不为1时
- 设置新的层叠上下文时isolation
- will-change 提前告知浏览器需要对元素做一些优化
- 裁剪:如果超出块的高度或者宽度 生成滚动条时
-
隐式合成 层级低的元素被提升层级高度之后,所有比它高的都需要提升,如果元素过多的话,会造成GPU一下子压力变大,直接让页面崩溃,这就是层爆炸。
-
生成绘制列表
渲染器会将图层的绘制,生成一个待执行的绘制列表,比如先化边框还是先画背景,为后续的绘制做准备
-
生成图块和位图
绘制列表准备好之后
渲染进程的主线程会给合成线程发送消息,视图就那么大,一下子给太多的让我绘制,非常浪费性能,所以合成线程先将图层分块,通常是256256 512512这个规格,可以让绘制效率大大提升。 优化:因为图块也是会进入GPU,考虑到浏览器内存上传GPU还是会慢,所以chrome团队先上传低分辨率的图块,等到正常的图块上传完成再替换低分辨率的图块,这样就加快了首屏的渲染。合成线程会把图层附近的图块交给栅格化线程,让它生成位图,生成的位图最后发给合成线程,合成线程会生成一个绘制指令,给到浏览器进程。-
显示器展示
浏览器进程接收到绘制指令,把页面内容绘制存放在浏览器内存里,也就是页面,发送给显卡,显示器显示。 以上浏览器的绘制就结束了
-
渲染拓展
-
重绘和重排是什么
根据上面的流程我们知道了整个浏览器的渲染流程,也知道渲染的主流程为哪些。
- 重绘 重绘 顾名思义就是重新绘制样式,不涉及到dom元素的改变和几何元素(宽高,位置) 所以流程上只会改动样式计算和绘制列表
- 重排/回流
- 能造成重排的属性
-
盒子模型相关: width、height、padding、border、margin、display、border-width、min-height
-
定位属性及浮动: top、right、bottom、left、position、float、clear
-
节点内部文字结构,行内属性 font-size、line-height
- 能造成重排的操作
- 读写位置属性时,比如 offset/scroll/client 等属性时会触发回流。
从生成布局树之后全部走一遍 - 调用 window.getComputedStyle 方法
从样式计算之后全部走一遍 - DOM 元素的几何属性(width/height/padding/margin/border)发生变化时会触发回流
从样式计算之后全部走一遍 - DOM 元素移动、删除、增加会触发回流。
从头开始渲染
-
从实际工作触发 了解这些之后 有什么感想
- 减少样式操作 + 尽量使用class改变样式 而不是通过js获取样式 一个一个改,减少回流与重绘的次数
- 减少DOM操作
- 插入元素尽量使用createDocumentFragment文档片段,因为文档片段是存在内存的,不会涉及到回流。
- 修改元素时要先克隆一下元素等操作好之后再次删除原有节点,插入即可。一次操作。
- 避免频繁直接访问计算后的样式,而是先将信息保存下来。一下代码不可取。
- 新建图层:将频繁重绘回流的dom元素单独作为一个独立图层,因此缩小了重绘和回流的影响范围。
- html不要嵌套太深, 否则会加大对页面布局的计算消耗
- 绝对布局的DOM, 不会造成大量回流
for(var i = 0;i<=10;i++){
var body = document.getElementsByTagName('body')[0]
var h = body.offsetHeight;}
VNode 虚拟Dom
-
什么是虚拟dom
一个对象,对象里面有tag标识,childern
-
虚拟Dom的出现有哪些好处
可以实现跨端,改变元素的数据可以通过数据劫持,而不用去跟jquery一样先找到元素再去修改元素 再去设置元素。
vue-Diff
-
vue2.0
头头比较 nodeStart++,newNodeStart++ 尾尾比较 nodeEnd--,newNodeEnd-- 头尾比较 尾头比较
-
vue3.0
从头开始比较,找到不相同的跳出 i++;再从尾开始比较 e1--,e2--,中间的改变 根据最长递增子序列移动位置 参考文献: