性能优化与调试技巧 | 豆包MarsCode AI 刷题

108 阅读3分钟

在优化Javascript代码性能时,关注页面渲染效率和代码执行效率尤为重要。

减少重回(Repaint)和重排(Reflow)

背景知识

  • 重排(Reflow):DOM结构或样式变化导致布局重新计算。

    • 触发条件:
      • 添加、删除DOM元素。
      • 元素的几何属性(如宽高、边距、内边距、边框、定位等)变化。
      • 浏览器窗口大小调整。
      • 修改CSS样式,如 displaywidthheight等。
    • 性能消耗: 重排需要重新计算布局和渲染树,性能开销较大,尤其是在复杂页面中会引起整棵DOM树的重新布局。
  • 重绘(Repaint):元素外观(如颜色)变化,不影响布局。

    • 触发条件:
      • 修改 colorbackground-colorvisibility等不改变几何属性的样式。
    • 性能消耗:相比重排,重绘的性能开销较小,因为不涉及布局的重新计算。
  • 重排比重绘消耗更多性能,频繁触发会导致页面卡顿。

优化策略

  1. 批量修改DOM:
    • 合并多次对DOM的操作
    • 使用DocumentFragment或隐藏元素后再修改
  2. 避免出发多次布局计算:
    • 缓存布局信息(如offsetHeightgetBoundingClientRect
    • 尽量减少样式的读取和写入交替操作

使用节流(Throttle)和防抖(Debounce)技术

背景知识

  • 节流(Throttle):规定在一定时间间隔内只执行一次函数。
  • 防抖(Debounce):在事件连续触发时,延迟执行函数,直到触发结束。

使用场景

  • 节流:滚动事件、窗口大小调整
  • 防抖:搜索框输入、按钮点击

节流函数:

function throttle(fn, delay) {
  let lastCall = 0;
  return function (...args) {
    const now = Date.now();
    if (now - lastCall >= delay) {
      lastCall = now;
      fn.apply(this, args);
    }
  };
}

防抖函数:

function debounce(fn, delay) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

使用性能分析工具

工具推荐

  • 浏览器开发者工具:
    • Performance面板:
      • 功能简介:
        • Performance面板是浏览器开发者工具中的一部分,用于分析页面加载和渲染的性能。
        • 通过记录和可视化浏览器执行过程,帮助开发者了解页面的性能瓶颈。
      • 关键功能:
        1. 页面加载分析:查看页面从加载到完全渲染的全过程,包括 DOMContentLoadedLoad 事件的触发时机。
        2. 帧率检测:可通过帧率图判断页面是否流畅,找出导致帧率下降的原因。
        3. 重排与重绘:详细显示哪些操作触发了回流(Layout)和重绘(Paint),帮助开发者减少不必要的性能消耗。
        4. JavaScript执行时间:显示脚本执行时间,识别耗时长的函数。
    • Lighthouse
      • 功能简介:
        • Lighthouse是Chrome内置的一款自动化性能分析 工具,可以生成网页的性能报告,并提供详细的优化 建议。
        • 适合用来检查页面的整体性能、可访问性和SEO。
      • 关键功能:
        1. 性能评分:根据核心性能指标(如页面加载速度、交互性等)生成性能评分。
        2. 问题定位与建议:提供具体的性能问题描述及解决建议,例如优化图片、减少无效的CSS和JS。
        3. 渐进式Web应用(PWA)检测:检查页面是否满足PWA标准。
        4. 可访问性与最佳实践:分析页面对不同用户的友好程度,如对视障用户的支持等。
  • 第三方库:
    • web-vitals:监控网站核心性能指标
    • Fps Meter:监控帧率(FPS)

其他优化技巧

  1. 使用Web Worker:
    • 将计算密集型任务从主线程分离,避免阻塞页面渲染
    const worker = new Worker('worker.js');
    worker.postMessage('start');
    worker.onmessage = (e) => {
      console.log('结果:', e.data);
    };
    
  2. 延迟加载资源:
    • 图片懒加载:<img loading='lazy' src='example.jpg'/>
    • 动态加载模块:import()
  3. 减少不必要的事件监听:
    • 使用事件委托,避免对子元素逐一绑定事件
    document.getElementById('parent').addEventListener('click', (e) => {
      if (e.target.matches('.child')) {
        console.log('子元素点击');
      }
    });
    
  4. 代码分片:
    • 使用requestIdleCallback执行非紧急任务
    requestIdleCallback(() => {
      console.log('页面空闲时执行任务');
    });
    

通过以上方法,结合场景需求对代码进行优化,可以显著提高JavaScript的性能和用户体验。