Skip to content

客户端渲染

什么是客户端渲染?
服务端会把静态资源给浏览器,浏览器运行一遍js,生成页面 页面的内容,在html源文件找不到(因为js没运行,就没的HTML DOM节点)

服务端渲染

什么是服务端渲染? 服务器会把完整的html给浏览器,浏览器不必跑一遍js才生成html页面 页面的内容,在html源文件找的到

服务端渲染不是性能万金油,把浏览器干的活都给服务器了,服务器表示鸭梨山大

浏览器渲染的过程

解析HTML(发出外部资源请求【DOM树】)->
计算样式(加载css与DOM和合并生成render树,伪元素也在这个环节被构建到DOM树中【CSSOM树】)->
计算图层布局(元素的相对位置、大小信息【布局渲染树】) ->
绘制图层(把每一个页面图层转换为像素,对所有媒体文件进行解码)->
整合图层,得到页面(合并各个图层,将数据由CPU输出给GPU绘制于屏幕上【绘制渲染树】)

CSS渲染优化点

CSS引擎查找样式规则,是从右到左匹配的

  1. 避免使用通配符(会遍历每一个元素)
  2. 关注可以通过继承实现的属性,避免重复匹配重复定义
  3. 少用标签选择器(#app li{} -> .app-li {})
  4. 减少嵌套。后代选择器开销最高,深度最好不超过3层

关于阻塞的优化

HTML、CSS、JS都具有阻塞渲染的特性

浏览器在构建CSSOM的过程中,不会渲染任何已处理的内容,哪怕DOM已经OK了

所以CSS是阻塞渲染的资源,需要尽早(css放在head中)尽快(CDN静态资源服务)的下载到客户端

JS引擎独立于渲染引擎,HTML解析器遇到script标签时,暂停渲染过程,将控制权交给JS引擎,JS引擎对内联代码直接执行,外部JS则去下载,在执行,等JS引擎运行完毕,浏览器才会把控制权交给渲染引擎

  • 一般情况
    <script src="index.js"></script>阻塞浏览器,需要等index.js加载和执行完毕
  • async <script async src="index.js"></script>加载是异步的,加载后,脚本立即执行
  • defer <script defer src="index.js"></script>加载是异步的,执行也是推迟的,执行在整个文档解析完成,DOMContentLoaded事件即将被触发时

回流与重绘

回流

  • 回流(重排):对DOM的修改引起了DOM几何尺寸的变化,比如大小、宽高、是否隐藏等,浏览器需要重新计算元素的几何属性,然后再绘制出来,这个过程称为回流
  • 重绘:修改了DOM的样式,但没有影响几何属性,比如修改了颜色,浏览器重绘即可 重绘不一定回流,回流一定重绘

这两个都应该减少,即减少DOM操作
DocumentFragment则是这个思想,它不是真实DOM树的一部分,对它修改不会引起回流和重绘,操作完DocumentFragment再统一做一次DOM的操作

引起回流:
1.改变几何属性width、padding、margin、left、boder等
2.改变DOM树结构,节点的增减和移动(开销还凑合)
3.获取offsetTop、scollTop、clientTop等,因为需要即时计算得到,会回流
4.getComputedStyle,也是即时计算得到,会回流

避免回流:
1.不要在循环里,多次获取offsetTop值,可以缓存在外面,计算完再一次性设置
2.不要逐条修改样式,可以合并作为一个类名,统一修改
3.将DOM离线,设置为display:none,再操作(频繁操作的话可以使用)

浏览器并不是在每一次修改都会回流,浏览器维护了一个flush队列,只有在不得已的时候才会回流(比如获取即时性属性)

宏任务与微任务

宏任务:setTimeout、setInterval、setImmediate、script整体代码、I/O操作、UI渲染 微任务:process.nextTick、Promise、MutataionObserver等

异步任务中进行DOM更新,需要包装为微任务