你不知道的chrome performance调试技巧

8,667 阅读6分钟

前言

Hello 大家好! 我是前端 无名

背景

昨天在刷掘金的时候,看到零一01大神写的一篇文章 我优化了进度条,页面性能竟提高了70%,下面的评论许多人想了解chrome的调试技巧,自己反思了一下,经常看见大神性能调优,嗖嗖的打开chrome performance 面板,一顿猛如虎的操作,然后就能发现性能问题。作为小白的我, 看的是一脸懵逼,what? 昨晚赶紧抓紧时间看看chrome 开发者中心,我要成为大神!

image.png

案例

  1. 演示demo ,这里对比三种方案,来结合chrome performance 面板进行讲解。

本文demo代码基于 chrome Developers 修改,增加一种优化方案来进行对比。

方案一 00_00_00-00_00_30.gif

部分代码片段

  app.update = function (timestamp) {
      for (var i = 0; i < app.count; i++) {
        var m = movers[i];
        if (app.scheme==1) {
            //方案一
            console.log("未优化的代码");
          var pos = m.classList.contains('down') ?
              m.offsetTop + distance : m.offsetTop - distance;
          if (pos < 0) pos = 0;
          if (pos > maxHeight) pos = maxHeight;
          m.style.top = pos + 'px';
          if (m.offsetTop === 0) {
            m.classList.remove('up');
            m.classList.add('down');
          }
          if (m.offsetTop === maxHeight) {
            m.classList.remove('down');
            m.classList.add('up');
          }
        }else if(app.scheme==2){
            console.log("方案二优化后的代码");
           
            var pos = parseInt(m.style.top.slice(0, m.style.top.indexOf('px')));
            m.classList.contains('down') ? pos += distance : pos -= distance;
            if (pos < 0) pos = 0;
            if (pos > maxHeight) pos = maxHeight;
             m.style.top = pos + 'px';
            if (pos === 0) {
              m.classList.remove('up');
              m.classList.add('down');
            }
            if (pos === maxHeight) {
              m.classList.remove('down');
              m.classList.add('up');
            }
        }else if(app.scheme===3){
                console.log("方案三优化后的代码");
                var pos = parseInt(m.style.transform.slice(m.style.transform.indexOf('(')+1, m.style.transform.indexOf('px')));
                m.classList.contains('down') ? pos += distance : pos -= distance;
                if (pos < 0) pos = 0;
                if (pos > maxHeight) pos = maxHeight;
                //   m.style.top = pos + 'px';
                m.style.transform=`translateY(${pos}px)`;
                if (pos === 0) {
                m.classList.remove('up');
                m.classList.add('down');
                }
                if (pos === maxHeight) {
                m.classList.remove('down');
                m.classList.add('up');
            }
        }
      }
      frame = window.requestAnimationFrame(app.update);
    }

开始

我们结合Performance 面板来查找上述案例性能瓶颈。

  1. 为了保障我们的界面性能不受其他chrome 插件影响,我们以隐身模式打开谷歌浏览器,具体打开方法如下:
  • Windows、Linux 或 Chrome 操作系统:按 Ctrl + Shift + n
  • Mac:按 ⌘ + Shift + n
  1. F12 打开DevTools 选择Performance

  2. 我们可以模拟移动CPU,选择x4 会比平常慢4倍。

image.png

记录运行时性能

针对演示demo ,方案一,我们可以很清楚的看到,页面上蓝色小方块增加到200的时候,fps已经从60降到了18左右,出现明显的卡顿效果,这个时候我们就需要在性能面板中进行录制,了解如何检测性能瓶颈。

  1. 在Performance面板中,点击Record(左上角小红圆点),开始录制。

image.png

  1. 稍微等上几秒钟。

  2. 点击stop。 devTool会停止记录,处理数据,过一会就会自动在性能面板显示结果。

image.png

到了这里看图表就比较懵逼了,这么多图形,该看那个呢,都是啥意思!

分析结果

获得页面性能后,我们怎么衡量页面的性能有没有问题呢?

FPS

衡量一个动画性能的重要指标就是FPS(每秒的帧数)。当动画以60FPS运行时,我们肉眼看上去动画是非常连贯的。

bad: image.png

good:

image.png

当我们看到FPS上方显示红色条的时候,意味着我们的帧率特别低,用户体验特别不好。一般来说,绿色条越高,FPS越高。 所以我们分析性能图标第一眼看的就是FPS。

CPU

FPS下方会有CPU图表。 bad:

image.png

good:

image.png

在性能面板底部,图形图表的色彩越多,意味着CPU性能已经达到极限。当我们看到CPU长时间处于最大值状态,就需要考虑怎样去优化。

选取指定时间位置的屏幕截图

将鼠标悬停在FPS、CPU或者NET图表上,DevTools显示当前页面的屏幕截图,左右移动鼠标,可以范围范围选取。这对于手动分析动画性能很有用。

image.png

Frames

image.png

在Frames部分,将鼠标悬浮在绿色方块上,DevTools会显示特定的帧消耗时间。每帧可能远低于60FPS的目标。

上图中一帧耗费446.2ms,那么它的FPS为2。(1000ms/446) 大约是2FPS。远远低于60FPS的要求。

更直观的工具:FPS meter

  1. 按 Command+Shift+P (Mac) 或 Control+Shift+P(Windows、Linux)打开命令菜单。

  2. 输入show Rendering

3.在 Rendering 选项卡中勾选FPS meter

image.png

  1. 我们就能实时的看到FPS数据了。

image.png

寻找性能瓶颈

image.png

我们已经知道性能有问题了,但是具体问题是什么引起的呢?

  1. 我们首先要看Summary选项卡,我们可以看到蓝色部分占用了大部分,蓝色代表Rendering,该页面大部分时间用于渲染。那我们就需要尝试去减少渲染时间。

  2. 展开main 部分。这里展示的是随时间变化主线上的火焰图。X轴表示时间,Y轴表示事件。每一个条形代表一个事件,条形越长,消耗时间越长。当看到图形堆叠,表示同一时间处理事件较高。会导致性能问题。 bad: image.png good:

image.png

  1. 我们可以看到Animation Frame Fired 右上角有红色三角形。PS:红色三角表示可能存才与此事件相关问题的警告,注意:只要执行requestAnimationFrame() 就会有此回调。

  2. 单击Animation Frame Fired,底部Summary 栏会显示有关该事件信息,并附带链接。单击链接会跳转到源码相关行。

image.png

image.png

  1. 上图中能看出是调用app.update引起问题。

  2. 选择app.update事件,我们可以看到有一堆的紫色事件。看基本每个都有红色的三角形。随便选择一个,我们可以在Summary选项卡中看到更多信息。有一个forced reflows (强制回流)的警告。

image.png

我们点击链接进入源码可以看到:

image.png

原因找到了是由于:offsetTop导致发生回流。

ps:回流比重绘更加消耗性能,付出的代价更高。

问题原因

image.png

我们采用 offsetTop导致发生回流引起性能消耗。

上图可以看出,回流一定会导致重绘,重绘不一定导致回流。

哪些会引起回流呢?

  1. 改变dom元素的几何属性,常见的几何属性有 width、height、padding、margin、left、top、border 等等。
  2. 改变dom树的结构,主要指的是增加或减少dom节点,移动等操作。
  3. 获取一定特殊的属性值,如属性:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 时,你就要注意了!除此之外:调用了 getComputedStyle 方法,也会触发回流。

优化

原来用anime.js 的时候,文档中有个介绍:

image.png

大多数CSS属性都会导致布局更改或重新绘制,并会导致动画不稳定。 因此尽可能优先考虑opacity和CSS transforms。

本文demo代码基于 chrome Developers 修改,代码中方案二是官方的优化方案:获取style.top值,去修改top值。

方案二:官方优化了一部分,去除offsetTop获取top值,但还是在修改top值,下面为官方的优化效果:

方案二 00_00_00-00_00_30.gif

200节点的时候为38fps

方案三:修改top为修改transforms

方案三 00_00_00-00_00_30.gif

优化后,我们可以看到200节点平稳的在60fps。

优化后preformance 图表效果

image.png

后语

现学现卖,我也要成为大神,欢迎大家多提意见。一赞一回!欢迎评论。