前端性能优化


前端性能优化指标RAIL

直接看这个文章前端性能优化 - 用RAIL模型分析性能


前端性能优化手段

前端总结–性能优化


重排重绘

网页生成的时候,至少会渲染一次。在用户访问的过程中,还会不断触发重排(reflow)和重绘(repaint)重排重绘都会消耗性能,其中重排会消耗比较多的性能,需尽量避免

重绘不一定会导致重排,重排一定会导致重绘

重排(reflow)

概念

当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排

重排也叫回流,简单的说就是重新生成布局,重新排列元素

下面情况会发生重排

  • 页面初始渲染,这是开销最大的一次重排
  • 添加/删除可见的DOM元素
  • 改变元素位置
  • 改变元素尺寸,比如边距、填充、边框、宽度和高度等
  • 改变元素内容,比如文字数量,图片大小等
  • 改变元素字体大小
  • 改变浏览器窗口尺寸,比如resize事件发生时
  • 激活CSS伪类(例如::hover)
  • 设置 style 属性的值,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow
  • 查询某些属性或调用某些计算方法:offsetWidth、offsetHeight等,除此之外,当我们调用 getComputedStyle方法,或者IE里的 currentStyle 时,也会触发重排,原理是一样的,都为求一个“即时性”和“准确性”。

重排影响的范围
由于浏览器渲染界面是基于流式布局模型的,所以触发重排时会对周围DOM重新排列,影响的范围有两种:

  • 全局范围:从根节点html开始对整个渲染树进行重新布局
  • 局部范围:对渲染树的某部分或某一个渲染对象进行重新布局
    把一个dom的宽高之类的几何信息定死,然后在dom内部触发重排,就只会重新渲染该dom内部的元素,而不会影响到外界

重绘

当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘

etg: color background border-style 等;

重排优化

  • 减少重排范围

    • 尽可能在低层级的DOM节点上
    • 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围
  • 减少重排次数

    • 样式集中改变
    • 分离读写操作
    • 将 DOM 离线
      • 使用 display:none
      • 通过 documentFragment 创建一个 dom 碎片,在它上面批量操作 dom,操作完成之后,再添加到文档中,这样只会触发一次重排
      • 复制节点,在副本上工作,然后替换它
    • 使用 absolutefixed 脱离文档流
    • 优化动画
      • 可以把动画效果应用到 position属性为absolutefixed 的元素
      • 启用GPU加速 GPU 硬件加速
// 样式集中改变
// bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top = top + "px";

// 当top和left的值是动态计算而成时...
// better 
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

// better
el.className += " className";

// 分离读写操作
// bad 强制刷新 触发四次重排+重绘
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
div.style.right = div.offsetRight + 1 + 'px';
div.style.bottom = div.offsetBottom + 1 + 'px';


// good 缓存布局信息 相当于读写分离 触发一次重排+重绘
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
var curRight = div.offsetRight;
var curBottom = div.offsetBottom;

div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
div.style.right = curRight + 1 + 'px';
div.style.bottom = curBottom + 1 + 'px';

/*
  * 根据上面的结论
  * 将 2d transform 换成 3d
  * 就可以强制开启 GPU 加速
  * 提高动画性能
  */
  div {
    transform: translate3d(10px, 10px, 0);
  }

白屏

SSR

服务端渲染,在服务端将渲染逻辑处理好,然后将处理好的HTML直接返回给前端展示,这样就可以解决白屏的问题,也可以解决seo的问题

预渲染

通过 webpackprerender-spa-plugin 编译应用中的静态页面,并将其输出到对应的索引目录

骨架屏

骨架屏的实现原理和预加载类似,都是利用了Puppeteer爬取页面的功能,Puppeteer是chrome出的一个headlessChromenode库,提供了API可以抓取SPA并生成预渲染内容,和预加载不太一样的是骨架屏技术会在Puppeteer生成内容后,利用算法将生成的内容进行替换,生成骨架页面


大量图片加载优化

  • 首屏图片优先加载,等首屏图片加载完全后再去加载非首屏图片。
  • 对大部分图片,减少图片体积,减少网络开销,加快下载速率

动画性能

  • 将动画设为绝对定位属性
  • 开启硬件加速,尽量避免浏览器创建不必要的图形层
    • transform
    • opacity
    • filter
  • 尽量减少js动画,如需要,使用对性能友好的requestAnimationFrame
    window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
    回调函数执行次数通常是每秒60次,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配 即 屏幕支持的 FPS
  • 使用chrome performance工具调试动画性能

渲染合成层

JavaScript:JavaScript实现动画效果,DOM元素操作等。
Composite(渲染层合并):对页面中 DOM 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常

合成层创建标准
什么情况下能使元素获得自己的层?虽然 Chrome的启发式方法(heuristic)随着时间在不断发展进步,但是从目前来说,满足以下任意情况便会创建层:

  • 3D 或透视变换(perspective transform) CSS 属性
  • 使用加速视频解码的 元素 拥有 3D
  • (WebGL) 上下文或加速的 2D 上下文的 元素
  • 混合插件(如 Flash)
  • 对自己的 opacity 做 CSS动画或使用一个动画变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
  • 元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

合成层的优点:

  • 有自己的绘图上下文,并且会开启硬件加速,有利于性能提升
  • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
  • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
  • 对于 transformopacity 效果,不会触发 layoutpaint

性能优化点:

  1. 提升动画效果的元素 合成层的好处是不会影响到其他元素的绘制,因此,为了减少动画元素对其他元素的影响,从而减少paint,我们需要把动画效果中的元素提升为合成层。 提升合成层的最好方式是使用 CSS 的 will-change属性。从上一节合成层产生原因中,可以知道 will-change设置为opacitytransformtopleftbottomright 可以将元素提升为合成层。
  2. 使用 transform 或者 opacity 来实现动画效果, 这样只需要做合成层的合并就好了。
  3. 减少绘制区域 对于不需要重新绘制的区域应尽量避免绘制,以减少绘制区域,比如一个 fix 在页面顶部的固定不变的导航header,在页面内容某个区域 repaint 时,整个屏幕包括 fix 的 header 也会被重绘。而对于固定不变的区域,我们期望其并不会被重绘,因此可以通过之前的方法,将其提升为独立的合成层。减少绘制区域,需要仔细分析页面,区分绘制区域,减少重绘区域甚至避免重绘

参考文章

重排(reflow)和重绘(repaint))

首页白屏优化实践

前端浏览器动画性能优化

浏览器渲染流程&Composite(渲染层合并)简单总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值