1. 用户从输入网址到看到页面,中间经历了哪些过程
请求阶段
1.URL编码 (请求的地址中如果出现非有效 UNICODE 编码内容,现代版浏览器会默认的进行编码)
2.DNS域名解析
DNS本地解析: 客户端 -> 浏览器缓存 -> 本地Hosts文件 <--> 本地DNS解析器缓存 <- -> 本地DNS服务器
非本地解析:DNS本地解析 -> 域名服务器(根域名服务器/顶级域名服务器)
DNS优化:
DNS一般会在第一次建立连接后缓存,时间很短
- 减少DNS解析次数:一个网站中我们需要发送请求的域名和服务器尽可能少即可
- DNS预获取(dns-prefetch):在页面加载开始的时候,就把当前页面中需要访问其他域名(服务器)的信息进行提前DNS解析,以后加载到具体内容部分可以不用解析了
3.建立 TCP 连接(TCP的三次握手)
4.发送HTTP请求
包含HTTP请求报文(包含起始行、请求头、请求主体)和响应报文(HTTP状态码、响应头、响应主体)
渲染阶段
1.生成DOM树
将服务器返回的十六进制的编码字节数据转换成我们能看到的代码,再通过词法解析将标签生成DOM节点,最后通过每个DOM节点之间的关系生成DOM树
2.生成CSSOM规则树
DOM树和CSSOM规则树是同时生成
3.通过DOM树 + CSSOM树生成整个渲染树
浏览器是多线程的,主要线程有; GUI渲染线程(负责渲染和绘制页面)、JS引擎线程(运行JS代码)、事件管控和触发线程、定时管控和触发线程、HTTP请求线程
在CSS渲染的过程中,有两种处理:
在解析html的过程中,在遇到link引入的样式时,浏览器会开辟一个新的HTTP请求线程去拿CSS内容,这时候GUI线程会继续向下渲染(无论CSS有没有拿到)。
如果是遇到@import导入的样式,则不会开辟新的线程,还是在当前线程同步加载,在没有拿到CSS内容前,后面的内容(css代码)不会继续渲染,所以CSS加载有时会阻塞渲染。
上面两种请求都会有请求时间的消耗,在样式代码不多的情况下,推荐使用内联样式(把html和css写在一起),这样只要html加载完,css也可以渲染完。如果html代码比较多,就不推荐采用这种方式了,会造成第一次请求html的时间变长。
在渲染的过程中,如果遇到JS会停止渲染,执行JS代码,因为浏览器有GUI渲染线程和JS引擎线程,为了放在渲染出现不可预期的结果,这两个线程是互斥的关系,JS的加载、解析与执行会阻塞DOM的构建,等JS引擎运行完毕,浏览器再从中断的地方恢复构建,所以很多优化方案都建议将script标签放在页面底部,当然也不是必须放在页面底部,放在头部也可以,只需要给script标签加上defer或async属性。
由于JS也可以操作样式,所以在加载js之前,浏览器会确保CSSOM的构建,会等待正在请求的css加载完,才会执行JS的加载,所以CSSOM的加载也会阻塞JS的执行。
4.布局,渲染树构建完成后,浏览器开始计算元素的大小和位置
浏览器器在测量元素大小和位置的过程通常叫回流(也称重构或重排,英文是 reflow)
可以这么理解,对节点的尺寸、位置修改,新增和删除节点,内容文本和窗口大小的变化都会造成回流
5.绘制,在布局完成后,将节点属性绘制到屏幕上的过程叫重绘
在绘制阶段,浏览器会呈现器,将呈现器的内容显示在屏幕上