直接跳到内容

JavaScript 性能优化

JavaScript 性能基础

JavaScript 性能优化关注执行效率、内存管理和运行时特性。现代 JavaScript 引擎采用即时编译、内联缓存和隐藏类优化等技术,但代码编写方式仍显著影响最终性能。优化核心是减少主线程阻塞,避免长任务导致的界面冻结。

特点:JavaScript 优化需要在开发效率和运行时性能间平衡。微优化在特定场景有效,但架构级优化通常收益更大。理解 V8 引擎工作机制是高效优化的前提。

示意图: JavaScript 执行流程: 解析 → 字节码生成 → 解释执行 → 热点识别 → 优化编译 → 反优化 性能陷阱:类型变化 → 隐藏类失效 | 大对象分配 → 垃圾回收压力 | 同步操作 → 主线程阻塞

代码分割与懒加载

代码分割将应用拆分为按需加载的块,减少初始包体积。动态 import() 实现路由级和组件级分割,Webpack SplitChunksPlugin 提取公共依赖。懒加载延迟非关键资源加载时机,提升首屏性能。

特点:分割粒度影响加载性能和缓存效率。过细分割增加请求开销,过粗分割失去按需加载优势。预加载关键包,预获取可能使用的包。

javascript
// 路由级代码分割
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

// 组件级懒加载
const HeavyComponent = lazy(() => 
  import('./components/HeavyComponent').then(module => ({
    default: module.HeavyComponent
  }))
);

// 预加载策略
const preloadMap = {
  '/about': () => import('./pages/About'),
  '/contact': () => import('./pages/Contact')
};

// 鼠标悬停时预加载
function onLinkHover(route) {
  if (preloadMap[route] && !preloaded[route]) {
    preloadMap[route]();
    preloaded[route] = true;
  }
}

长任务分割与调度

长任务 (超过 50ms 的连续执行) 阻塞主线程,导致界面无响应。通过任务分解、异步执行和空闲期调度,将长任务拆分为可中断的短任务。requestIdleCallback 在浏览器空闲期执行低优先级任务,requestAnimationFrame 确保动画流畅。

特点:任务分割需要考虑任务原子性和状态一致性。调度策略应基于任务优先级和用户交互状态。

javascript
// 使用requestIdleCallback分割任务
function processLargeData(data, callback) {
  const chunkSize = 1000;
  let index = 0;
  
  function processChunk(deadline) {
    while (index < data.length && deadline.timeRemaining() > 0) {
      // 处理数据块
      processItem(data[index]);
      index++;
    }
    
    if (index < data.length) {
      // 继续在下一个空闲期处理
      requestIdleCallback(processChunk);
    } else {
      // 全部完成
      callback?.();
    }
  }
  
  requestIdleCallback(processChunk);
}

// 使用requestAnimationFrame优化动画计算
function smoothAnimation() {
  let startTime = null;
  
  function animate(timestamp) {
    if (!startTime) startTime = timestamp;
    const progress = timestamp - startTime;
    
    // 计算下一帧状态(保持轻量)
    const newPosition = calculatePosition(progress);
    updateElementPosition(newPosition);
    
    if (progress < 1000) {
      requestAnimationFrame(animate);
    }
  }
  
  requestAnimationFrame(animate);
}

// 任务优先级调度
class TaskScheduler {
  constructor() {
    this.highPriorityTasks = [];
    this.lowPriorityTasks = [];
    this.isProcessing = false;
  }
  
  addTask(task, priority = 'low') {
    const queue = priority === 'high' ? 
      this.highPriorityTasks : this.lowPriorityTasks;
    queue.push(task);
    this.scheduleProcessing();
  }
  
  scheduleProcessing() {
    if (this.isProcessing) return;
    
    if (this.highPriorityTasks.length > 0) {
      this.processHighPriority();
    } else if (this.lowPriorityTasks.length > 0) {
      this.processLowPriority();
    }
  }
  
  processHighPriority() {
    this.isProcessing = true;
    const task = this.highPriorityTasks.shift();
    
    // 同步执行高优先级任务
    task();
    
    if (this.highPriorityTasks.length > 0) {
      // 继续处理下一个高优先级任务
      setTimeout(() => this.processHighPriority(), 0);
    } else {
      this.isProcessing = false;
      this.scheduleProcessing();
    }
  }
  
  processLowPriority() {
    this.isProcessing = true;
    
    requestIdleCallback((deadline) => {
      while (this.lowPriorityTasks.length > 0 && deadline.timeRemaining() > 0) {
        const task = this.lowPriorityTasks.shift();
        task();
      }
      
      this.isProcessing = false;
      if (this.lowPriorityTasks.length > 0 || this.highPriorityTasks.length > 0) {
        this.scheduleProcessing();
      }
    });
  }
}

内存管理与垃圾回收

JavaScript 内存管理基于自动垃圾回收,但不当引用仍导致内存泄漏。优化策略包括及时释放引用、避免全局变量、使用对象池复用对象。WeakMap 和 WeakSet 不阻止垃圾回收,适合缓存场景。

特点:内存优化重点是识别和防止泄漏,而非微观管理。性能分析工具监控内存使用模式,发现异常增长。

javascript
// 对象池实现
class ObjectPool {
  constructor(createFn, resetFn = (obj) => obj) {
    this.createFn = createFn;
    this.resetFn = resetFn;
    this.freeList = [];
    this.count = 0;
  }
  
  acquire() {
    if (this.freeList.length > 0) {
      return this.freeList.pop();
    }
    this.count++;
    return this.createFn();
  }
  
  release(obj) {
    this.resetFn(obj);
    this.freeList.push(obj);
  }
  
  // 使用示例:向量对象池
  static vectorPool = new ObjectPool(
    () => ({ x: 0, y: 0 }),
    (vec) => { vec.x = 0; vec.y = 0; }
  );
}

// 避免内存泄漏的模式
function createEventListener(element) {
  const handler = () => { /* 处理逻辑 */ };
  element.addEventListener('click', handler);
  
  // 提供清理方法
  return () => {
    element.removeEventListener('click', handler);
  };
}

// 使用WeakMap做缓存(不阻止垃圾回收)
const weakCache = new WeakMap();
function getExpensiveValue(object) {
  if (!weakCache.has(object)) {
    const value = computeExpensiveValue(object);
    weakCache.set(object, value);
  }
  return weakCache.get(object);
}

函数优化与执行效率

函数级别优化包括减少重复计算、优化热路径和使用高效算法。记忆化缓存计算结果,内联小函数减少调用开销,避免在热循环中创建对象。

特点:函数优化应基于性能分析数据,避免过早优化。关注算法复杂度,但实际性能受常数因子和硬件特性影响。

javascript
// 记忆化优化
function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

// 防抖与节流优化频繁调用
function debounce(func, wait, immediate = false) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      timeout = null;
      if (!immediate) func.apply(this, args);
    };
    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(this, args);
  };
}

function throttle(func, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// 热路径优化:减少函数调用和对象创建
function optimizedHotPath(data) {
  // 预先计算长度避免重复访问
  const len = data.length;
  let result = 0;
  
  // 使用局部变量缓存频繁访问的属性
  const { property } = data;
  
  for (let i = 0; i < len; i++) {
    // 内联简单计算,避免函数调用开销
    result += property[i] * property[i];
  }
  
  return result;
}

DOM 操作优化

DOM 操作是 JavaScript 性能主要瓶颈。优化策略包括批量更新、减少重排重绘、使用文档碎片和事件委托。虚拟 DOM 库通过差异比对最小化实际 DOM 操作。

特点:DOM 访问比 JavaScript 执行慢几个数量级。读写分离减少布局抖动,离线操作避免中间渲染。

javascript
// 批量DOM更新
function batchDOMUpdates(elements, updates) {
  // 触发批量更新前
  const fragment = document.createDocumentFragment();
  
  updates.forEach(update => {
    const element = document.createElement(update.tag);
    element.textContent = update.content;
    fragment.appendChild(element);
  });
  
  // 单次插入到DOM
  container.appendChild(fragment);
}

// 减少重排重绘
function efficientStyleChanges(element) {
  // 触发一次重排
  element.style.display = 'none';
  
  // 批量修改样式(不会触发重排)
  element.style.width = '100px';
  element.style.height = '200px';
  element.style.padding = '10px';
  
  // 触发一次重排
  element.style.display = 'block';
}

// 使用requestAnimationFrame集合DOM更新
let scheduledUpdate = false;
const pendingUpdates = new Set();

function scheduleUpdate(callback) {
  pendingUpdates.add(callback);
  
  if (!scheduledUpdate) {
    scheduledUpdate = true;
    requestAnimationFrame(() => {
      scheduledUpdate = false;
      const updates = Array.from(pendingUpdates);
      pendingUpdates.clear();
      
      updates.forEach(update => update());
    });
  }
}

// 事件委托优化
document.getElementById('list').addEventListener('click', function(event) {
  if (event.target.tagName === 'LI') {
    // 处理列表项点击,无需为每个li绑定监听器
    handleItemClick(event.target);
  }
});

异步操作优化

异步代码优化关注 Promise 性能、异步函数开销和并发控制。避免 Promise 构造函数重复执行同步代码,优化 async/await 使用模式,限制并发请求数量。

特点:异步操作优化减少微任务队列压力,避免内存泄漏。错误处理不影响性能关键路径。

javascript
// Promise优化模式
class PromiseOptimizer {
  // 缓存Promise结果
  static cache = new Map();
  
  static cachedAsyncOperation(key, operation) {
    if (this.cache.has(key)) {
      return this.cache.get(key);
    }
    
    const promise = operation().finally(() => {
      // 可选的缓存过期策略
      setTimeout(() => this.cache.delete(key), 30000);
    });
    
    this.cache.set(key, promise);
    return promise;
  }
  
  // 并发控制
  static async limitedConcurrency(tasks, limit) {
    const results = [];
    const executing = new Set();
    
    for (const task of tasks) {
      if (executing.size >= limit) {
        await Promise.race(executing);
      }
      
      const promise = task().finally(() => {
        executing.delete(promise);
      });
      
      executing.add(promise);
      results.push(promise);
    }
    
    return Promise.all(results);
  }
}

// 优化的async/await模式
async function optimizedAsyncFlow() {
  // 并行发起不依赖的请求
  const [user, settings] = await Promise.all([
    fetchUser(),
    fetchSettings()
  ]);
  
  // 避免不必要的await
  const validationPromise = validateUser(user);
  const processingPromise = processSettings(settings);
  
  // 需要结果时再await
  const [isValid, processedSettings] = await Promise.all([
    validationPromise,
    processingPromise
  ]);
  
  return { user: isValid ? user : null, settings: processedSettings };
}

模块与打包优化

模块系统优化关注 Tree Shaking 效果、循环引用处理和动态导入开销。使用 ES 模块确保静态分析,避免运行时动态导入影响关键路径。

特点:模块结构影响打包工具优化能力。深层嵌套导入增加解析开销,Barrel 文件 (索引文件) 可能阻碍 Tree Shaking。

javascript
// 优化模块结构
// 避免:
// export * from './utils'; // 阻碍Tree Shaking

// 推荐:明确导出
export { formatDate } from './dateUtils';
export { debounce } from './functionUtils';
export { storage } from './storageUtils';

// 动态导入优化
const getHeavyModule = () => {
  let modulePromise = null;
  
  return () => {
    if (!modulePromise) {
      // 预加载但不阻塞
      modulePromise = import('./heavyModule.js')
        .then(module => module.default)
        .catch(error => {
          modulePromise = null; // 失败时重置
          throw error;
        });
    }
    return modulePromise;
  };
};

// 使用Intersection Observer触发动态加载
const lazyLoadModule = (element, modulePath, callback) => {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        import(modulePath).then(module => {
          callback(module.default);
        });
        observer.unobserve(entry.target);
      }
    });
  });
  
  observer.observe(element);
};

性能监控与检测

运行时性能监控识别实际性能瓶颈。Performance API 测量具体操作耗时,Long Tasks API 检测阻塞任务,Memory API 监控内存使用。

特点:性能监控应同时关注实验室数据和真实用户数据。监控代码本身需要优化,避免影响测量结果。

javascript
// 性能测量工具
class PerformanceMonitor {
  static measurements = new Map();
  
  static startMeasure(name) {
    this.measurements.set(name, {
      startTime: performance.now(),
      startMemory: performance.memory?.usedJSHeapSize
    });
  }
  
  static endMeasure(name) {
    const measurement = this.measurements.get(name);
    if (!measurement) return null;
    
    const duration = performance.now() - measurement.startTime;
    const memoryUsed = performance.memory ? 
      performance.memory.usedJSHeapSize - measurement.startMemory : 0;
    
    this.measurements.delete(name);
    
    return { duration, memoryUsed };
  }
  
  // 自动测量函数执行
  static measureFunction(fn, context = null) {
    return function(...args) {
      this.startMeasure(fn.name);
      try {
        return fn.apply(context, args);
      } finally {
        const result = this.endMeasure(fn.name);
        if (result && result.duration > 100) {
          console.warn(`Slow function ${fn.name}: ${result.duration}ms`);
        }
      }
    }.bind(this);
  }
}

// 长任务监控
if ('PerformanceObserver' in window) {
  const observer = new PerformanceObserver((list) => {
    list.getEntries().forEach((entry) => {
      if (entry.duration > 50) {
        console.warn('Long task detected:', entry);
        // 上报到监控系统
      }
    });
  });
  
  observer.observe({ entryTypes: ['longtask'] });
}

// 内存监控
function monitorMemory() {
  if (performance.memory) {
    const memory = performance.memory;
    const used = memory.usedJSHeapSize;
    const limit = memory.jsHeapSizeLimit;
    
    if (used / limit > 0.9) {
      console.warn('High memory usage detected');
    }
  }
}

setInterval(monitorMemory, 30000);
JavaScript 性能优化已经加载完毕