总的来说就是
【开辟一个‘GUI’渲染线程,自上而下解析代码,最后绘制出对应页面】
接下来详细说
自上而下解析代码的过程是同步的,但是有些操作是异步的
-
遇到css资源的加载
- 遇到的是
<style>“内嵌样式” =>“同步” 交给GUI渲染线程解析,(大哥自己亲自去渲染) - 遇到的是
<link>外链样式 =>“异步” 开辟一个新的“HTTP网络请求线程” (派小弟去,不等小弟,自己的渲染完再去解析小弟的)
注意:同一个源下,根据不同的浏览器,最多只允许同时开辟4~7个HTTP线程 “HTTP的并发数” ,可以把http线程想象成小弟,GUI线程是大哥。 不等待资源信息请求回来,GUI渲染线程继续向下渲染
GUI渲染线程同步操作都处理完成后,再把基于HTTP图片络线程请求回来的资源文件进行解析渲染 - 遇到
@import导入式样式 (派小弟去,一直等小弟,小弟回来接着渲染,会阻碍渲染)
“同步” 开辟一个新的“HTTP网络请求线程”去请求资源文件
但是在资源文件没有请求回来之前,GUI渲染线程会被“阻塞”,不允许其继续向下渲染
- 遇到的是
-
遇到
<script>资源的请求- 默认都是“同步”的:必须基于HTTP网络线程,把资源请求回来之后,并且交给“JS渲染线程”渲染解析完成后,GUI渲染线程才能继续向下渲染,所以
<script>默认也是“阻碍GUI渲染”的 (大哥自己亲自去渲染) - async属性:遇到
<script async>首先也是开辟一个HTTP网络线程去请求加载资源文件,与此同时GUI渲染线程继续向下渲染「把默认的同步改为“异步”」,但是一旦当资源请求回来后,会中断GUI的渲染,先把请求回来的JS进行渲染解析 (派小弟去,不等小弟,小弟回来就去渲染小弟带回来的) - defer属性:遇到
<script defer>和async类似,都是新开辟HTTP网络线程去请求加载资源文件,与此同时GUI还会继续渲染「“异步”」,但是不一样的地方是,defer和link类似,是在GUI同步的代码渲染完成后,才会渲染解析请求回来的JS代码 (派小弟去,不等小弟,自己的渲染完再去解析小弟的)
- 默认都是“同步”的:必须基于HTTP网络线程,把资源请求回来之后,并且交给“JS渲染线程”渲染解析完成后,GUI渲染线程才能继续向下渲染,所以
-
遇到
<img>或者音视频- 遇到这些资源,也会发送新的HTTP网络线程,请求加载对应的资源文件,不会阻碍GUI的渲染「“异步”」;当GUI渲染完成后,才会把请求回来资源信息进行渲染解析;(派小弟去,不等小弟,自己的渲染完再去解析小弟的)
页面的渲染步骤
- DOM TREE(DOM树):自上而下渲染完页面,整理好整个页面的DOM结构关系
- CSSOM TREE(样式树):当把所有的样式资源请求加载回来后,按照引入CSS的顺序,依次渲染样式代码,生成样式树
- RENDER TREE(渲染树):把生成的DOM树和CSSOM树合并在一起,生成渲染树(设置display:none的元素不进行处理)
- Layout 布局/回流/重排: 根据生成的渲染树,计算它们在设备视口(viewport)内的确切位置和大小
- 分层处理:按照层级定位分层处理,每一个层级都有会详细规划出具体的绘制步骤
- Painting:按照每一个层级计算处理的绘制步骤,开始绘制页面
性能优化【CRP关键渲染路径】
- 生成dom树
- 减少层级嵌套
- 不使用非标准的标签
- 生成om树
- 尽可能不使用@import
- 如果css代码较少,尽可能使用‘style内嵌样式’
- 如果使用link,尽可能把所有的样式资源合并为一个,且压缩(因为http并发性,渲染css的时候也不需要再计算依赖关系)
- css的选择链短一些(css选择器渲染是从右向左的)
- 把link等导入css的操作放在head中(一加载就开始请求资源)
- 对于其他资源的优化
- 对于script ,尽可能放置再页面底部,防止阻碍GUI渲染
- 对于img,懒加载,第一次加载页面的时候不要加载请求图片,占据了HTTP的并发数量
- 重排/重绘
- 对于第一次绘制,都会经历重排和重绘
- 重排必然引起重绘,重绘不会引起重排,所以优化重点在重绘
- 重绘优化
- 总方法,不要自己去操作Dom,例如vue/react
- 样式读写分离,把修改样式和获取样式的代码分离开
- 新增元素:a.文档碎片b.把动画等频发的样式改变的操作,运用到position:fixed/absolute上,脱离文档流,单独一层
- 修改样式的transform/opacity...,不会引发DOM的回流【弊端是消耗浏览器的内存】