前端性能优化——渲染优化

122 阅读3分钟

现代浏览器网页渲染原理,关键渲染路径( critical rendering path )

javascript(交互、动画等视觉变化) -> style(样式重新计算) -> layouts(布局) -> paint(绘制) -> composite(图层组合)

  • 1,浏览器构建对象模型
    • 浏览器构建 DOM 对象,html -> DOM
    • 构建 CSSOM 对象,css -> CSSOM
  • 2,浏览器构建渲染树,DOM + CSSOM -> Render Tree 结合渲染路径,有一些样式并不需要执行布局和绘制的步骤,这样渲染速度就会被加快,也是性能优化的一个思路

回流与重绘,如何避免布局抖动

布局与绘制,再次布局又叫做回流 reflow
  • 渲染树只包含网页需要的节点
  • 布局是计算每个节点精确的位置和大小 - 盒模型
  • 绘制是像素化每个节点的过程
影响回流的操作
  • 添加、删除元素
  • 操作 styles
  • display: none
  • offsetLeft/offsetTop/clientWidth
  • 移动元素位置
  • 修改浏览器大小,字体大小

tips:有一些动画是使用 GPU 进行加速的,这种动画效果不会触发布局和重绘,而直接进行复合的过程。

避免布局抖动( layout thrashing )
  • 避免回流,比如用 transform 中的 translate 来做位移,避免回流和重绘。
  • 读写分离,比如第三方框架使用 vdom
使用 FastDom 插件防止布局抖动
  • 如何使用 FastDom Apis
复合线程( composition thread )与图层( layers )
  • 将页面拆分图层进行绘制再进行复合
  • 利用 DevTools 了解网页的图层拆分情况
  • 仅影响复合的样式
减少重绘( repaint )

只影响复合的属性,比如 transform/opacity。把只影响复合的元素提取到一个单独的图层里

  • 利用 DevTools 识别 paint 的瓶颈
  • 利用 will-change 创建新的图层
高频事件防抖,解救页面卡顿

利用 Chrome DevTools 打开时可以复现抖动的问题( pointer events ) 对一些高频事件做一些长处理,就容易出现抖动问题,可以使用 requestAnimationFrame 函数解决这个问题。

image.png rAF 是执行在布局和绘制之前的函数 对于高频率触发的事件,一帧之内多次触发处理函数是没有意义的,一帧之内触发一次就可以了,这时候就可以使用去抖动( debounce )。去抖动就是把原来频率很高的一个事情,变成按照需要的频率触发一次。

let ticking = false;
window.addEventListener('pointermove',e => {
    let pos = e.clientX;
    if(ticking) return;
    ticking = true;
    window.requestAnimationFrame(()=>{
        changeWidth(pos)
    })
})
React 时间调度实现

React16 做了一个较大的革新,实现了一个 fiber 机制。可以将 DOM 的修改,一个批量的任务拆解为许多的小任务,然后通过时间调度实现完成,从而保证用户交互的空闲时间。React 时间调度的实现就是借用了 rAF 方法。 基本原理:

  • requestIdleCallback 的问题
    • requestIdleCallback 是一帧 16ms 时间还有空余的时间的情况下,再做一些事情,但是这个函数没有被浏览器很好的支持
  • 所以 React 通过 rAF 模拟 rIC

在一帧的关键渲染周期内