各位性能调优师们,欢迎来到网站加速的秘密基地!本章我们将把慢吞吞的"乌龟网站"改造成敏捷的"猎豹应用"。准备好让你的代码起飞了吗?
14.1 代码优化技巧 - 给JavaScript"瘦身"
变量与作用域优化
// 坏味道
function processData(data) {
let result = [];
for (let i = 0; i < data.length; i++) {
let item = data[i];
let processedItem = doSomething(item);
result.push(processedItem);
}
return result;
}
// 优化版
function processData(data) {
return data.map(doSomething); // 简洁高效
}
循环优化实战
// 低效写法
const arr = [/* 大数组 */];
for (let i = 0; i < arr.length; i++) { // 每次读取length
// ...
}
// 优化方案
for (let i = 0, len = arr.length; i < len; i++) { // 缓存length
// ...
}
// 最佳方案
arr.forEach(item => { /*...*/ }); // 或者使用for...of
防抖与节流 - 控制函数调用频率
// 防抖:最后一次操作后等待执行
function debounce(fn, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, arguments), delay);
};
}
// 节流:固定时间间隔执行
function throttle(fn, interval) {
let lastTime = 0;
return function() {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, arguments);
lastTime = now;
}
};
}
// 使用场景:滚动事件
window.addEventListener('scroll', throttle(handleScroll, 100));
14.2 内存管理 - 避免"内存泄漏"陷阱
常见内存泄漏场景
// 1. 意外的全局变量
function leak() {
globalVar = '这是一个全局变量'; // 忘记var/let/const
}
// 2. 未清理的定时器
let timer = setInterval(() => {
// 即使元素被移除了,定时器还在运行!
}, 1000);
// 正确做法
function cleanUp() {
clearInterval(timer);
}
// 3. DOM引用未释放
const elements = {
button: document.getElementById('myButton'),
div: document.getElementById('myDiv')
};
function removeDiv() {
document.body.removeChild(elements.div);
// 即使移除了DOM,elements.div依然保持引用
}
内存优化实践
// WeakMap/WeakSet 允许被垃圾回收
const weakMap = new WeakMap();
let domNode = document.getElementById('node');
weakMap.set(domNode, '一些数据');
// 当domNode被移除后,weakMap中的条目会自动清除
14.3 加载性能优化 - 让页面秒开
资源加载策略
<!-- 延迟加载非关键JS -->
<script src="analytics.js" defer></script>
<!-- 预加载重要资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="prefetch" href="next-page-data.json" as="fetch">
<!-- 懒加载图片 -->
<img data-src="real-image.jpg" src="placeholder.jpg"
loading="lazy" alt="示例图片">
代码分割实战
// 动态导入实现按需加载
document.getElementById('btn').addEventListener('click', async () => {
const module = await import('./heavy-module.js');
module.doSomething();
});
// Webpack自动代码分割配置
// output: {
// filename: '[name].[contenthash].bundle.js',
// chunkFilename: '[name].[contenthash].chunk.js'
// }
14.4 渲染性能优化 - 60FPS的流畅体验
减少重排与重绘
// 糟糕的做法
function moveElement(element) {
element.style.left = '100px'; // 重排
element.style.top = '200px'; // 重排
element.style.width = '300px'; // 重排
}
// 优化方案
function moveElement(element) {
// 使用CSS类一次性修改
element.classList.add('new-position');
}
// 或者使用requestAnimationFrame
function animate(element) {
let pos = 0;
function frame() {
if (pos < 300) {
pos++;
element.style.left = pos + 'px';
requestAnimationFrame(frame);
}
}
requestAnimationFrame(frame);
}
虚拟列表优化长列表
class VirtualList {
constructor(container, items, itemHeight) {
this.container = container;
this.items = items;
this.itemHeight = itemHeight;
this.visibleCount = Math.ceil(container.clientHeight / itemHeight);
this.startIndex = 0;
container.style.position = 'relative';
container.style.overflow = 'auto';
this.render();
container.addEventListener('scroll', () => {
this.startIndex = Math.floor(container.scrollTop / itemHeight);
this.render();
});
}
render() {
// 只渲染可见项
const endIndex = this.startIndex + this.visibleCount;
const visibleItems = this.items.slice(this.startIndex, endIndex);
// 更新容器高度
this.container.style.height = `${this.items.length * this.itemHeight}px`;
// 渲染可见项
const fragment = document.createDocumentFragment();
visibleItems.forEach((item, index) => {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.top = `${(this.startIndex + index) * this.itemHeight}px`;
div.textContent = item;
fragment.appendChild(div);
});
this.container.innerHTML = '';
this.container.appendChild(fragment);
}
}
// 使用
new VirtualList(
document.getElementById('list'),
Array.from({length: 10000}, (_, i) => `Item ${i+1}`),
50
);
本章总结:
- 代码优化:精简逻辑,减少计算量
- 内存管理:及时清理,避免泄漏
- 加载优化:按需加载,预取资源
- 渲染优化:减少重排,高效更新
性能检测工具:
- Chrome DevTools Performance面板
- Lighthouse综合评分
- WebPageTest多地点测试
- Memory面板检查内存泄漏
实战练习:
- 分析你之前项目的性能瓶颈
- 实现图片懒加载组件
- 优化一个存在大量DOM操作的页面
- 使用Webpack进行代码分割
性能优化检查清单:
- [ ] 最小化JavaScript文件
- [ ] 使用Tree Shaking移除无用代码
- [ ] 压缩图片资源
- [ ] 启用Gzip/Brotli压缩
- [ ] 使用CDN分发静态资源
- [ ] 添加合适的缓存策略
- [ ] 减少第三方库依赖
- [ ] 避免同步布局抖动
- [ ] 使用CSS动画代替JS动画
- [ ] 实施代码分割和懒加载
下一章我们将深入调试与测试的世界,学习如何像侦探一样追踪bug!准备好你的放大镜了吗?