JavaScript性能优化技巧

一、先搞懂:为啥要做 JS 性能优化?

简单说,JS 执行慢会导致「页面卡、点击没反应、加载久」—— 比如滑动页面卡顿、按钮点了半天才响应、白屏时间长。优化的核心就是「少执行、快执行、不阻塞」。

二、核心优化技巧(附实操案例)

1. 代码层面:让代码跑得更快

这是最基础也最易落地的,改几行代码就能见效。
  • 减少不必要的 DOM 操作(性能头号杀手)DOM 操作是 JS 里最慢的操作之一,尽量「批量操作、少查少改」:❌ 错误示范(频繁操作 DOM):
    javascript
     
    运行
     
    // 循环里每次都查DOM、改DOM,卡到爆
    for (let i = 0; i < 1000; i++) {
      document.getElementById('list').innerHTML += `<li>${i}</li>`;
    }
     
     
    ✅ 优化方案(先拼字符串 / 文档片段,再一次性插入):
    javascript
     
    运行
    let html = '';
    const list = document.getElementById('list');
    for (let i = 0; i < 1000; i++) {
      html += `<li>${i}</li>`; // 先在内存里拼字符串
    }
    list.innerHTML = html; // 只操作1次DOM
     
  • 避免重复计算,缓存结果把频繁用到的计算结果、DOM 查询结果存起来,不用每次都算 / 查:❌ 错误示范(重复查 DOM + 计算):
    javascript
     
    运行
     
     
     
     
    // 每次调用都查DOM、算offsetTop,浪费性能
    function getPosition() {
      return document.getElementById('box').offsetTop + 10;
    }
    // 循环里反复调用
    for (let i = 0; i < 100; i++) {
      console.log(getPosition());
    }
     
     
    ✅ 优化方案(缓存结果):
    javascript
     
    运行
    // 只查1次、算1次
    const boxTop = document.getElementById('box').offsetTop + 10;
    function getPosition() {
      return boxTop;
    }
    for (let i = 0; i < 100; i++) {
      console.log(getPosition());
    }
     
     
  • 优化循环与条件判断
    • 循环:减少循环内的操作,用for代替for-in/forEach(大数据量下for更快);
    • 条件判断:多分支用switch或对象映射代替多层if-else,减少判断次数。
       
      ✅ 示例(对象映射替代 if-else):
    javascript
     
    运行
    // 多层if-else → 对象映射,查找更快
    const actionMap = {
      'add': () => console.log('添加'),
      'delete': () => console.log('删除'),
      'edit': () => console.log('编辑')
    };
    // 调用:直接取,不用逐个判断
    actionMap['add']?.();
     
     
  • 使用高效的数据结构
    • 查数据:用Map/Set代替数组(Mapget/has是 O (1),数组find/includes是 O (n));
    • 去重 / 判存:Set比数组indexOf/includes快 10 倍以上。
       
      ✅ 示例(Set 去重):
    javascript
     
    运行
    // 数组去重:Set比循环+indexOf快得多
    const arr = [1,2,2,3,3,3];
    const uniqueArr = [...new Set(arr)]; // [1,2,3]
     
     

2. 运行时:避免阻塞页面渲染

JS 是单线程的,执行耗时操作会阻塞页面加载 / 交互,核心是「异步、拆分、延迟」。
  • 异步处理耗时操作网络请求、大数据计算等耗时操作,用async/await/Promise异步执行,不阻塞主线程:✅ 示例(异步加载数据):
    javascript
     
    运行
    // 异步请求数据,不阻塞页面渲染
    async function loadData() {
      try {
        const res = await fetch('/api/data');
        const data = await res.json();
        renderData(data); // 数据回来后再渲染
      } catch (err) {
        console.error(err);
      }
    }
    // 页面加载后再执行,不阻塞首屏
    window.addEventListener('DOMContentLoaded', loadData);
     
  • 拆分长任务,给主线程 “喘气” 机会单个任务执行超过 50ms 就会让页面卡顿,用requestIdleCallbacksetTimeout拆分长任务:✅ 示例(拆分循环任务):
    javascript
     
    运行
     
    // 长循环拆分,避免阻塞主线程
    const data = new Array(100000).fill(0);
    let index = 0;
    function processChunk() {
      // 每次只处理1000条,避免一次执行太久
      const end = Math.min(index + 1000, data.length);
      for (; index < end; index++) {
        data[index] = data[index] * 2;
      }
      if (index < data.length) {
        // 把下一次执行放到下一个事件循环
        setTimeout(processChunk, 0);
      }
    }
    processChunk();
     
  • 延迟加载非核心代码(懒加载)首屏用不到的 JS(比如弹窗、二级页面逻辑),等页面加载完成后再加载:✅ 示例(懒加载模块):
    javascript
     
    运行
     
    // 点击按钮时才加载弹窗模块,减少首屏JS体积
    document.getElementById('openModal').addEventListener('click', async () => {
      // 动态import,懒加载模块
      const { openModal } = await import('./modal.js');
      openModal();
    });

3. 资源加载:减少 JS 文件体积 & 加载时间

文件越小、加载越快,核心是「压缩、分包、按需加载」。
  • 压缩与混淆代码上线前用 Webpack/Vite/Terser 压缩代码(去掉空格、注释,缩短变量名),体积能减少 50% 以上;开启 Gzip/Brotli 压缩(服务器配置),JS 文件体积再减 60%~80%。
  • 代码分包(Code Splitting)把大 JS 文件拆成多个小文件,首屏只加载核心代码,其他代码按需加载(Webpack/Vite 自带该功能):✅ Vite 示例(分包配置):
    javascript
     
    运行
     
    // vite.config.js 配置分包,拆分第三方库(如React/Vue)
    export default {
      build: {
        rollupOptions: {
          output: {
            manualChunks: {
              // 把vue相关代码拆成单独的包
              vue: ['vue', 'vue-router'],
              // 把工具库拆成单独的包
              utils: ['lodash', 'axios']
            }
          }
        }
      }
    };
     
     
  • 使用 CDN 加载第三方库像 jQuery、Lodash、Vue 这些常用库,用 CDN 加载(比如阿里云 / 腾讯云 CDN),不用自己服务器分发,还能利用浏览器缓存。✅ 示例(CDN 加载 Vue):
    html
     
    预览
     
     
     
     
    <!-- 用CDN加载Vue,比本地加载快,还能缓存 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
     
     

4. 渲染联动:避免触发重排 / 重绘

JS 操作 DOM 会触发浏览器重排(Reflow)/ 重绘(Repaint),这两个操作超耗性能:
  • 减少重排 / 重绘触发
    • 改样式时,先把 DOM 设为display: none,改完再显示(只触发 2 次重排,而非多次);
    • transform/opacity做动画(GPU 加速,不触发重排),代替top/left
       
      ✅ 示例(GPU 加速动画):
    css
     
    /* 用transform做动画,不卡 */
    .box {
      transition: transform 0.3s;
    }
    .box:hover {
      transform: translateX(10px); /* 只触发重绘,不触发重排 */
      /* 不要用left: 10px; 会触发重排,卡顿 */
    }
     
     

三、优化效果验证(怎么知道优化有用?)

不用凭感觉,用浏览器工具测:
  1. Chrome DevTools → Performance:录制页面操作,看 JS 执行耗时、是否有长任务、重排 / 重绘次数;
  2. Lighthouse:生成性能报告,看 JS 加载 / 执行、首屏加载等指标;
  3. Console.time():测代码执行时间,对比优化前后:
    javascript
     
    运行
     
    // 测一段代码的执行时间
    console.time('loop');
    // 要测试的代码
    for (let i = 0; i < 100000; i++) {}
    console.timeEnd('loop'); // 输出:loop: 2.34ms

总结

  1. 核心原则:少操作 DOM、少阻塞主线程、减小文件体积、避免重排 / 重绘;
  2. 优先落地:批量 DOM 操作、缓存计算结果、异步处理耗时任务、代码分包;
  3. 验证方法:用 Chrome Performance/Lighthouse 量化优化效果,不凭主观判断。
posted @ 2025-12-24 17:38  爱吃牛腩  阅读(2)  评论(0)    收藏  举报