一、输入网址并解析
解析URL
输入URL后,浏览器会解析出协议、主机、端口、路径等信息,并构造一个HTTP请求。
- 浏览器发送请求前,根据请求头的
expires和cache-control判断是否命中(包括是否过期)强缓存策略,如果命中,直接从缓存获取资源,并不会发送请求。如果没有命中,则进入下一步。 - 没有命中强缓存规则,浏览器会发送请求,根据请求头的
If-Modified-Since和If-None-Match判断是否命中协商缓存,如果命中,直接从缓存获取资源。如果没有命中,则进入下一步。 - 如果前两步都没有命中,则直接从服务端获取资源。
HSTS
由于安全隐患,会使用 HSTS 强制客户端使用 HTTPS 访问页面。详见:你所不知道的 HSTS[1]。当你的网站均采用 HTTPS,并符合它的安全规范,就可以申请加入 HSTS 列表,之后用户不加 HTTPS 协议再去访问你的网站,浏览器都会定向到 HTTPS。无论匹配到没有,都要开始 DNS 查询工作了。
DNS解析
- 在发起http请求之前,浏览器首先要做去获得我们想访问网页的IP地址,浏览器会发送一个UDP的包给DNS域名解析服务器。
- 查询方法有递归查询、迭代查询
- DNS还能负载均衡,预解析
二、TCP/IP连接:三次握手
三、HTTP请求
HTTP2.0与HTTP1.1的区别
- 二进制协议
HTTP2.0是二进制协议,在HTTP1.1版本中,报文的头信息必须是文本,数据体可以是文本,也可以是二进制。HTTP2.0则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为“帧”,可以分为头信息帧和数据帧,帧的概念是它实现多路复用的基础
- 多路复用
HTTP2.0实现了多路复用,HTTP2.0仍然复用TCP连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了“队头阻塞”的问题
- 数据流
HTTP2.0使用了数据流的概念,因为HTTP2.0的数据包是不按顺序发送的,同一个链接里面连续的数据包,可能属于不同的请求,因此,必须要对数据包做标记,指出它属于哪个请求,HTTP2.0将每个请求或回应的所有数据包,称为一个数据流,每个数据流都有一个独一无二的编号,数据包发送时,都必须标记数据流ID用来区分它属于哪个数据流
- 头信息压缩
HTTP2.0实现了头信息压缩,由于HTTP1.1协议不带状态,每次请求都必须附上所有信息,所以,请求的很多字段都是重复的,比如COOKIE和useragent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度,HTTP2.0对这一点做了优化,引入了头信息压缩机制,一方面,头信息使用gzip或compress压缩后再发送,另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了
- 服务器推送
HTTP2.O允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必须要的资源,这样就可以相对减少一些延迟时间,这里需要注意的是HTTP2.0下服务器主动推送的是静态资源,和websocket以及SSE等方式向客户端发送即时数据的推送是不同的
HTTP3
- QUIC“快速UDP互联网连接”(Quick UDP Internet Connections)
HTTP3 的主要改进在传输层上。传输层不会再有我前面提到的那些繁重的 TCP 连接了。现在,一切都会走 UDP。
HTTPS
在HTTP的基础上再加一层TLS(传输层安全性协议)或者SSL(安全套接层),就构成了HTTPS协议。
HTTPS 默认工作在 TCP 协议443端口,它的工作流程一般如以下方式:
- TCP 三次同步握手
- 客户端验证服务器数字证书
- DH 算法协商对称加密算法的密钥、hash 算法的密钥
- SSL 安全加密隧道协商完成
- 网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的hash算法进行数据完整性保护,保证数据不被篡改。
四、服务器处理请求并返回HTTP报文
五、浏览器渲染页面
渲染流程:
- 获取DOM后分割为多个图层
- 对每个图层的节点计算样式结果 (Recalculate style--样式重计算)
- 为每个节点生成图形和位置 (Layout--重排,回流)
- 将每个节点绘制填充到图层位图中 (Paint--重绘)
- 图层作为纹理上传至GPU
- 组合多个图层到页面上生成最终屏幕图像 (Composite Layers--图层重组)
回流和重绘
- 重绘
当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
- 回流
当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
回流必将引起重绘,而重绘不一定会引起回流。
引起回流:
- 页面首次渲染
- 浏览器窗口大小发生改变
- 元素尺寸或位置发生改变
- 元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的DOM元素
- 激活CSS伪类(例如::hover)
- 查询某些属性或调用某些方法
引起回流的属性和方法:
- clientWidth、clientHeight、clientTop、clientLeft
- offsetWidth、offsetHeight、offsetTop、offsetLeft
- scrollWidth、scrollHeight、scrollTop、scrollLeft
- scrollIntoView()、scrollIntoViewIffNeeded()
- getComputedStyle()
- getBoundingClientRect()
- scrollTo()
如何减少回流
- css
- 避免使用table布局;
- 尽可能在DOM树的最末端改变class;
- 避免设置多层内联样式;
- 将动画效果应用到position属性为absolute或fixed的元素上;
- 避免使用CSS表达式(例如:calc())。
- JS
- 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
- 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
- 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
- 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。