什么!一个性能优化你问我 8 小时!!你在摸鱼还是我在摸鱼!!!

109 阅读6分钟

性能优化

面试?现在的环境我哪来的面试, 我只是个标题狗罢了!

image.png

performance

性能优化要结合性能分析来说。 可以通过 performance 选项卡先对项目进行分析。

  1. network

    • 如有加载耗时文件, 像vue elementUI,或者地图geojson文件 可以放cdn静态资源加速(这里可能会问为什么会加速,还会牵扯到一个知识点,公司搭建npm私服,不知道这个就赶紧说完.别给面试官机会)在vite/webpack 配置 externals打包排除。
      • ask:npm私服是什么, 解决什么问题, 如何搭建 。 npm私服
      • ask: 什么是cdn, 为什么cdn会加速 cdn科普
        • CDN(Content Delivery Network,内容分发网络)
        • 将网站的内容缓存到离用户最近的节点上, 网线变短了传输不就加快了吗。
    • 对于不重要的资源可以配置prefetch,让浏览器在空闲时间去加载,(如图片,视频, 其他非当前页面资源), 毕竟浏览器网络请求一次最多加载6个。 减少网络传输也可以提高页面加载 当然对于关键资源, 也可以加preload进行预加载。
      • ask: prefetch和preload作用区别?prefetch,preload
        • preload 预加载: 加载资源一般是当前页面需要的
        • prefetch 预读取: 一般是其它页面有可能用到的资源。
    • 顺口也可以说一下,目前像vue项目都会给打包之后的script标签增加defer属性, 让js本会在 HTML 文档完全解析完毕后执行 (毕竟说的越多显得你越吊)。
      • ask:script标签的 defer属性和async属性作用和区别 , defer和async
        • defer属性用于延迟加载脚本。这意味着浏览器会立即开始下载脚本,但不会阻塞 HTML 的解析。
        • async 属性用于异步加载脚本。这意味着浏览器会立即开始下载脚本,而不会阻塞 HTML 的解析。
  2. frames

    • 就是页面展示帧截图, 我也不知道有什么可以说的. 可以说页面的渲染帧16.666ms. 默认情况下 60fps 就是1秒刷新60次, 渲染帧就是 1 / 60 ≈ 16.67
  3. animation

    • 这里是动画,卡了就禁用吧, 优化的话。 可以适当的说使用GPU 渲染, css有几个属性可以开启GPU 渲染, will-change、 transform、opacity、filter (光栅化) 这里可能会问cpu, gpu 的区别, 不会也要赶紧跑. cpu,gpu详解,

      • ask: 为什么要用transform, 直接用transition修改width, height . 不也可以生成动画吗. 强制改变宽高会引起重绘还是回流?

        • 修改元素的布局,几何属性会导致页面回流

        • 修改不影响样式布局的属性会发生重绘

        • image that

          在一片沙滩(干的沙子)斜坡上, 你从上到下写了个A,B,C。你现在要改变沙B(中间一个)的颜色, 你直接一个喷漆, 哇: 绿了。对吧, 你重绘了,而且只影响了沙B, 即元素本身。

          所以你说:沙A,沙C没变(重绘不会导致回流)。

          但是你情种劲犯了:你拍了个照片发给你女朋友看,女朋友回你一句大煞笔。你思索片刻,得出结论, 你女朋友觉得这个沙B画大了一点。你就两只手按住了沙B的两端, 往中间挤了挤。沙B变小了。但是上面的沙A会流淌下来,沙C的位置也发生一点变化

          这个时候你说:沙A,沙C也动了呀(你改变了元素的几何属性,导致了页面回流, 重排一般也会导致重绘,嗯。有点道理。)

      • ask: 什么是重绘, 什么是回流. 有什么对应关系

        重绘: 在浏览器重新绘制网页以显示由 UI 更改引起的视觉更新时发生,例如在交互式站点上进行更新后。这通常是在重排之后发生的,重排是浏览器重新计算网页的某些部分的位置和几何形状。

        回流:mdn叫重排,发生在浏览器重新计算网页的某些部分的位置和几何形状时(例如在交互式站点更新后)。这通常会紧接着重绘(repaint),即浏览器重新绘制网页以显示更新后的视觉效果。

        重排/回流 重绘 重绘和回流

    • 拔高:利用 requestAnimationFrame 执行动画。requestAnimationFrame

  4. timings

    • 这里就是关键指标的加载, 不展开了

      • LCP - largest Contentful Paint
      • CLS - Cumulative Layout Shift
      • INP - Interaction to Next Paint
    • ask: 网页如何获取这些指标? (直接上代码吧)

      const timing = performance.timing;
      
          // 1. 白屏时间(First Paint)
          const firstPaint = performance.getEntriesByName('first-paint')[0]?.startTime;
          console.log('白屏时间 (First Paint):', firstPaint !== undefined ? `${firstPaint.toFixed(2)} ms` : '未记录');
      
          // 2. 首屏时间(First Contentful Paint, FCP)
          const firstContentfulPaint = performance.getEntriesByName('first-contentful-paint')[0]?.startTime;
          console.log('首屏时间 (First Contentful Paint, FCP):', firstContentfulPaint !== undefined ? `${firstContentfulPaint.toFixed(2)} ms` : '未记录');
      
          // 3. 用户可交互时间(Time to Interactive, TTI)
          const timeToInteractive = timing.domInteractive - timing.navigationStart;
          console.log('用户可交互时间 (Time to Interactive, TTI):', timeToInteractive !== undefined ? `${timeToInteractive.toFixed(2)} ms` : '未记录');
      
          // 4. 页面完全加载时间(Load Event End)
          const loadTime = timing.loadEventEnd - timing.navigationStart;
          console.log('页面完全加载时间 (Load Event End):', loadTime !== undefined ? `${loadTime.toFixed(2)} ms` : '未记录');
      
          // 5. CLS, LCP, FID, INP, FCP 指标通过 Web Vitals 获取
          // CLS (Cumulative Layout Shift)
          onCLS((metric) => {
            console.log('累积布局偏移 (CLS):', metric.value !== undefined ? `${metric.value.toFixed(2)}` : '未记录');
          });
      
          // LCP (Largest Contentful Paint)
          onLCP((metric) => {
            console.log('最大内容绘制时间 (LCP):', metric.value !== undefined ? `${metric.value.toFixed(2)} ms` : '未记录');
          });
      
          // FID (First Input Delay)
          onFID((metric) => {
            console.log('首输入延迟 (FID):', metric.value !== undefined ? `${metric.value.toFixed(2)} ms` : '未记录');
          });
      
          // INP (Input Delay)
          onINP((metric) => {
            console.log('用户输入延迟 (INP):', metric.value !== undefined ? `${metric.value.toFixed(2)} ms` : '未记录');
          });
      
          // FCP (First Contentful Paint)
          onFCP((metric) => {
            console.log('首屏内容绘制时间 (FCP):', metric.value !== undefined ? `${metric.value.toFixed(2)} ms` : '未记录');
          });
      
          // TTFB (Time to First Byte) 需要使用 Performance API 直接获取
          const ttfb = performance.getEntriesByType('navigation')[0]?.responseStart - performance.timing.navigationStart;
          console.log('首字节时间 (TTFB):', ttfb !== undefined ? `${ttfb.toFixed(2)} ms` : '未记录');
      
  5. Main

    • 火焰图,性能优化的关键,也是放大镜找屎入口。这里越红,你代码越臭。

    • 找到红色部分, long task。

      点击查看summary, 先看总结, 到底是哪部分出了问题,如果是Scripting ,进入call tree 去一点点往下找找到你可以改的代码,观察一下是否是写的不合理, 由于现在框架的发展。 这里一般都不会有太多问题或者说太多能改的问题。

      这里也可以说利用requestIdleCallback 执行耗时任务。requestIdleCallback

      treeshaking 进行树摇打包去除无用的死代码.(对于一些全局引入的插件很有用, vite已经默认启用treeshaking)

      ...这里可以说的太多了, 有兴趣的看着补充吧

lighthouse

  • 用来生成性能分析报告, 记录关键指标
  1. Performance

  2. Accessibility

  3. Best Practices

  4. SEO

    不敢问,暂时没研究太多。。。

Performance monitor

  • 运行时性能检测,打开控制台 ctrl + shift + p, 搜索一下 performance monitor就可以出来了。
  1. cpu usage。 cpu使用率, 看看你的网页消耗多少算力cpu一直居高不下, 很大概率就是过了一会你的网页就出现 “哎哟,崩溃了~”。
  2. js heap size。 可以检测运行时你的内存有没有泄露。 观察曲线走势, 和数字。 是否一致增加, 是的话就要检测代码中存在内存泄漏的地方了
  3. Dom Nodes , 可以检测游离节点是否一致增加。
  4. Js event listeners, 监听事件个数(游离节点多了, 可能也会导致这个变多)
  5. Documens
  6. Document Frames
  7. Layout /sec 应该是每秒的偏移量。 猜测跟指标 CLS 有点类似
  8. Style recalcs / sec。。。