如何提升 JavaScript 代码的性能

发布: (2025年12月19日 GMT+8 15:56)
4 min read
原文: Dev.to

Source: Dev.to

1. 理解 JavaScript 执行模型

现代 JavaScript 引擎(V8、SpiderMonkey、JavaScriptCore)依赖即时编译(JIT)、内联缓存、隐藏类/形状以及投机性优化。

避免触发去优化(De‑Optimization)

引擎会根据观察到的类型对函数进行优化。执行过程中更改类型会迫使去优化。

// Avoid this
function sum(a, b) {
  return a + b;
}

sum(1, 2);       // optimized for numbers
sum("1", "2");   // de‑optimizes

// Do this
function sum(a, b) {
  a = Number(a);
  b = Number(b);
  return a + b;
}

2. 形状稳定性与对象访问

JavaScript 对象使用隐藏类。动态改变对象结构会阻止属性访问的优化。在遍历大数据集时,保持形状稳定可提升 20–50 % 的性能。

// Avoid this
const user = {};
user.name = "Alice";
user.age = 30;
user.isAdmin = true;

// Do this
const user = {
  name: "Alice",
  age: 30,
  isAdmin: true
};

3. 减少垃圾回收压力

垃圾回收(GC)会暂停执行。高分配率会导致频繁的 GC 循环。应避免在热点路径中进行不必要的分配。

// Excessive allocation
function process(items) {
  return items.map(item => ({
    id: item.id,
    value: item.value * 2
  }));
}

// Object reuse
function process(items) {
  const result = new Array(items.length);
  for (let i = 0; i < items.length; i++) {
    const item = items[i];
    result[i] = {
      id: item.id,
      value: item.value * 2
    };
  }
  return result;
}

循环 vs. 函数式方法

// Using map / filter / reduce
const total = items
  .filter(p => p > 10)
  .map(p => p * 1.2)
  .reduce((a, b) => a + b, 0);

// Optimized loop
let total = 0;
for (let i = 0; i < items.length; i++) {
  const p = items[i];
  if (p > 10) {
    total += p * 1.2;
  }
}

5. 异步性能:避免意外序列化

async/await 使用不当会引入隐藏的瓶颈。正确的并行可以把执行时间从 O(n × latency) 降到 O(max latency)。

// Serialized execution
async function fetchAll(urls) {
  const results = [];
  for (const url of urls) {
    results.push(await fetch(url));
  }
  return results;
}

// Parallel execution
async function fetchAll(urls) {
  return Promise.all(urls.map(fetch));
}

6. 记忆化与缓存失效

对确定性、耗时的函数避免重复计算。记忆化必须配合缓存大小限制和明确的失效规则;否则内存泄漏会抵消收益。

const cache = new Map();

function expensiveCalc(n) {
  if (cache.has(n)) return cache.get(n);

  let result = 0;
  for (let i = 0; i < n; i++) {
    result += Math.sqrt(i);
  }

  cache.set(n, result);
  return result;
}

DOM 批处理(读/写分离)

// Bad: interleaved reads and writes
elements.forEach(el => {
  el.style.width = el.offsetWidth + 10 + "px";
});

// Good: batch reads then writes
const widths = elements.map(el => el.offsetWidth);

elements.forEach((el, i) => {
  el.style.width = widths[i] + 10 + "px";
});

8. 测量,而不是猜测

使用可用的工具和 API 来测量性能。没有测量的优化就是盲目工程。

  • performance.now()
  • Chrome DevTools Performance 面板
  • Node.js --prof
  • Flamegraphs
const start = performance.now();
// critical code
const end = performance.now();
console.log(`Execution: ${end - start}ms`);

你的代码要么配合这些系统工作,要么主动与之抗争。稳定的类型、稳定的形状、受控的内存分配以及有意的异步行为,才能让引擎进行积极的优化。

Back to Blog

相关文章

阅读更多 »

裸机前端

Bare-metal frontend 介绍 现代前端应用已经变得非常丰富、复杂且精细。它们不再只是简单的 UI 轮询数据。它们……