利用浏览器的 performance,快速定位问题代码。

72 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 29 天,点击查看活动详情

利用浏览器的 performance,快速定位问题代码。

start

  • 记录一下使用 performance,排查问题的方法。

教程

演示的代码

<!DOCTYPE html>
  <head>
    <meta charset="UTF-8" />
    <title>lazy_tomato</title>
  </head>

  <body>
    <script>
      function a() {
        b()
      }
      function b() {
        let total = 0
        for (let i = 0; i < 10 * 10000 * 10000; i++) {
          total += i
        }
      }

      a()
    </script>
  </body>
</html>

可以看到上方的演示的代码,一个 html 页面,页面中有一个循环次数非常多的 for 循环(循环次数多方便我们演示)。

打开谷歌浏览器的performance,开始重新录制。

可以得到下图: image.png

寻找问题代码

Task 标红,表示这是一个长任务,需要优化。

左键点击选中,再点击底部的Boytom-Up,我们可以看到我们代码执行的耗时。右侧,可以链接到对应的代码区域。

image.png

image.png

上述的操作,就可以准确定位耗时比较久的代码。

优化问题代码

有两种优化思路:

  • 优化代码本身,或者直接去除部分代码。
  • 必须要执行此类代码,且无法优化。可以利用 new Worker 优化。

实践

最近小伙伴写了一个 Vue 的页面,页面操作起来有非常明显的卡顿。而且代码略微比较复杂,无法快速定位卡顿的原因。

解决思路:

  1. vue-devtools;
    • 既然是 Vue 页面,可以利用 Vue 官方的浏览器插件中的performance选项来检测我们页面的性能,可以快速定位我们性能开销较大的组件。
    • 但是页面本身就比较卡顿了,浏览器插件直接崩溃。
  2. 谷歌浏览器的performance;
    • 可以运行。

开始动手

基于第一小节学习的案例,我想利用performance快速定位问题代码。

直接打开对应页面,开启录制,然后操作页面,得到这么一个图表。

可以看到还是有很多标红的 task,查看总面板,主要是 script 的执行比较耗时。 在buttom-up中查找耗时比较久的代码

image.png

可以看到上述的截图,核心部分的代码是 Vue.js,其次还有我们自己编写的代码,看到右侧的文件名,我初步判断,这个方法getUUidByLabel有问题。

后续排查了一下逻辑,我这里列举一下伪代码

/* 1.有一个数组存储了一百个对象 */
var arr = []
for (let index = 0; index < 100; index++) {
  arr.push({
    uuid: index,
    label: 'tomato' + index,
  })
}

/* 2. 在数组中查找 label相同的项的 uuid */
function getUUidByLabel(label) {
  return arr.find((item) => item.label === label).uuid
}

/* 3. getUUidByLabel被大量重复调用(上千次) */

解决思路:

  • 首先优化了触发getUUidByLabel的逻辑,减少了调用次数。

    这个就涉及到具体业务逻辑了,就不细说了。

  • 其次对于getUUidByLabel的优化,目前想到两种:

    1. 调用 getUUidByLabel(label) 传入的 label 是固定的三种,较粗暴的情况下,可以放弃getUUidByLabel,使用常量替换。

    2. 缓存?

    缓存思路的代码

    /* 模仿 Vue.js源码中的函数缓存 */
    
    var arr = []
    for (let index = 0; index < 100; index++) {
      arr.push({
        uuid: index,
        label: 'tomato' + index,
      })
    }
    
    function cached(fn) {
      //一个空对象
      const cache = Object.create(null)
      return function cachedFn(str) {
        const hit = cache[str]
        return hit || (cache[str] = fn(str))
      }
    }
    
    const getUUidByLabel = cached((str) => {
      return arr.find((item) => item.label === str).uuid
    })
    
    console.log(getUUidByLabel('tomato3')) // 3
    
  • 优化后的效果 image.png

end

  • 到目前为止,算是自己尝试性能优化的第一步。

  • 希望自己越来越强,加油。