# 从输入url到渲染发生了什么
# 网路请求
- URl的解析
- 检查资源缓存
- DNS解析
- 建立TCP连接
- TLS协商密钥
- 发送请求&接受响应
- 关闭TCP连接
# URL解析
1、会把不完整的URL合成完整的URl。协议名+域名+端口+路径[+参数][+描点]: 例如输入www.baidu.com, 浏览器会自动将其拼接为https://www.baidu.com/, 默认使用443端口
2、URL中对于非安全字符转译时,使用的编码叫做百分号编码,因为它使用百分号加上两位的16进制数表示。 这两位十六进制数来自UTF-8编码,将每一个中文转换成3个字节,例如:在google中搜索中'中文',url会变成 /search?q=%E4%B8%AD%E6%96%87,一共6个字节。
我们常写的encodeURL和encodeURLComponent正是起这个作用的。区别是 = ? & ; /这些特殊符号在encodeURl 中不会被转译,因为编码的是整个URL,而encodeURLComponent编码的是参数部分,需要严格把关。
# 检查缓存
检查缓存一定是在发起真正缓存之前进行的,只有这样缓存的机制才会生效。如果发现有对应的缓存资源, 则去检查缓存 的有效期。
强缓存:expires
cache-control: private; // 允许客户端缓存 cache-control: public; // 允许客户端以及代理服务器缓存 cache-control: no-cache; // 协商缓存 cache-control: no-store; // 不允许缓存 cache-control: max-age; // 设置过期时间
协商缓存: last-modified/If-modified-since
Etag/If-none-match
# DNS解析
- 浏览器的DNS缓存
- 操作系统的DNS缓存
- 路由器的DNS缓存
- 根域名服务器
- 顶级域名服务器
- 主域名服务器
为了节约时间,我们可以在HTML头部去做DNS的预解析: 一次DNS解析需要耗费 20-120ms(为跨域的域名设置预解析)
<link rel="dns-prefetch" href="http://www.baidu.com" />
- 减少DNS请求次数
- 缩短DNS解析时间dns-prefetch 为了保证响应的及时,DNS解析使用的是UDP协议。
# 建立TCP连接
三次握手、四次挥手 因为三次是确保双方发送、接收功能完好的最少次数。
协商加密密钥-SSL 使用非对称和对称加密的方式
使用非对称加密的方式协商出一个对称密钥。
- 客户端发送一个随机值以及支持的协议和加密方式;
- 服务端收到客户端的随机值,发送自己的数字证书,附加上自己产生的一个随机值,并根据客户端支持的协议和 加密方式使用对应的公式
- 客户端收到服务端的CA证书,验证证书的有效性,验证通过后再生成一个随机值,通过服务端证书的公钥去加密这个随机值 并发给服务端。
- 服务端收到加密过的随机值,使用私钥解密获得第三个随机值,这时候两端都拥有了三个随机值。可以通过这个三个 随机值按照之前约定的加密方式生成了密钥,接下里就使用这个对称密钥来加密解密。
# 发送请求
请求行 + 请求头 + 请求体
响应行 + 响应头 + 响应体
# 结束请求
主动方会等待2MSL
MSL是指数据包在网络中最大的生存时间。目的是确保服务端收到了这个确认报文段,
假设服务端没有收到第四次握手的报文,试想一下会发生什么?在客户端发送第四次握手的数据包后, 服务端首先会等待,在1个MSL后,它发现超过了网络中数据包的最大生存时间, 但是自己还没有收到数据包,于是服务端认为这个数据包已经丢失了, 它决定把第三次握手的数据包重新给客户端发送一次,这个数据包最多花费一个MSL会到达客户端。
一来一去,一共是2MSL,所以客户端在发送完第四次握手数据包后, 等待2MSL是一种兜底机制,如果在2MSL内没有收到其他报文段, 客户端则认为服务端已经成功接受到第四次挥手,连接正式关闭。
# 浏览器渲染
- 生成DOM Tree
- 生成CSSOM
- 相结合,得到定位,图层,进行point,浏览器进行GUI绘制。
为什么css放到头部,js放到尾部
- css资源异步下载,下载和解析都不会阻塞dom树
- JS资源同步下载,下载和执行都会阻塞构建DOM树。
css会阻塞HTML解析嘛
GUI渲染进程可以一边解析HTML,一边解析CSS,这两个是不会冲突的。但是在加载JS时,无法同时进行解析。 因为JS有可能修改DOM,所以CSS有可能阻塞DOM的解析。
预加载扫描器是什么。
async/defer有什么差别
- async 属性表示异步执行引入的Javascript。乱序
- defer表示延迟DOM解析完成,再执行JS。顺序加载
prefetch preload有什么区别 (只加载,不执行)
- preload:以最高优先级为当前页面加载资源。应该在当前页面立即使用。
- prefetch:以低优先级为后面的页面加载未来需要的资源,只会在空闲时才去加载。 使用preload时,应配合as属性,表示该资源的优先级,使用 as="style" 属性将获得最高的优先级,
- as ="script"将获得低优先级或中优先级,其他可以取的值有font/image/audio/video;
preload字体时要加上crossorigin属性,即使没有跨域,否则会重复加载:
<link rel="preload href="font.woff" as="font" crossorigin>
# 结论
- 浏览器将输入内容解析后,拼接成完整的URL,其中的参数使用的是UTF-8编码,也就是我们开发时会常用的encodeURI和encodeURIComponent两个函数,其中encodeURI是对完整URL编码,encodeURIComponent是对URL参数部分编码,要求会更严格;
- 浏览器缓存的disk cache和memory cache分别是从磁盘读取和从内存中读取,通常刷新页面会直接从内存读,而关闭tab后重新打开是从磁盘读;
- 预加载prefetch是在空闲时间,以低优先级加载后续页面用到的资源;而preload是以高优先级提前加载当前页面需要的资源;
- 脚本的async是指异步加载,完成加载立刻执行,defer是异步加载,完成HTML解析后再执行;
- TCP握手需要三次的三次是为了保证客户端的存活,防止服务端资源的浪费,挥手要四次是因为TCP是双工通信,每一个方向的连接释放、应答各需要一次;
- HTTPS的握手是为了协商出一个对称密钥,双方一共发送三个随机数,利用这三个随机数计算出只有双方知道的密钥,正式通信的内容都是用这个密钥进行加密的;
← V8垃圾回收机制