如何提升 JavaScript 代码的性能
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`);
你的代码要么配合这些系统工作,要么主动与之抗争。稳定的类型、稳定的形状、受控的内存分配以及有意的异步行为,才能让引擎进行积极的优化。