1. 性能优化的核心概念
重绘 (Repaint) 与重排 (Reflow)
- 重绘:当元素的外观样式(如颜色、背景等)发生变化时,需要重新绘制,但不会影响布局。
- 重排:当元素的几何属性(如大小、位置等)发生变化时,会触发整个文档的重新布局,开销比重绘更大。
如何避免频繁的重排和重绘
-
减少 DOM 操作:
- 合并多次操作,使用文档片段(
DocumentFragment)。 - 避免频繁访问 DOM,改为缓存结果。
- 合并多次操作,使用文档片段(
-
使用 CSS 合理布局:
- 避免使用动态计算的样式属性(如
offsetHeight等)引发多次重排。
- 避免使用动态计算的样式属性(如
-
批量更新样式:
- 使用
classList一次性添加/删除类,而非逐条修改样式。
- 使用
实践示例
测试环境准备
1. HTML 结构 在页面中创建一个测试容器元素:
<div id="example" style="height: 200px; overflow: auto; border: 1px solid #000;"></div>
页面效果
2. 测试代码 将两段代码分别封装为可调用的函数:
function inefficientMethod() {
const element = document.getElementById('example');
for (let i = 0; i < 1000; i++) {
element.style.width = `${i}px`; // 频繁修改导致性能低下
}
}
function efficientMethod() {
const element = document.getElementById('example');
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.style.width = `${i}px`;
fragment.appendChild(div);
}
element.appendChild(fragment); // 一次性操作 DOM
}
3. 使用 console.time 测量执行时间
console.time('Inefficient Method');
inefficientMethod();
console.timeEnd('Inefficient Method');
console.time('Efficient Method');
efficientMethod();
console.timeEnd('Efficient Method');
通过 JavaScript 内置的性能计时方法测量代码块的运行时间:
- 如图在浏览器控制台查看两者的执行时间差异
2. 节流 (Throttle) 与防抖 (Debounce)
节流 (Throttle)
- 限制一个函数在指定时间内最多执行一次,适用于 连续触发的事件(如滚动、缩放) 。
实践示例:验证节流功能是否正常工作
测试环境准备
1. 在页面上添加一个滚动区域
<div style="height: 2000px; background: linear-gradient(to bottom, #fff, #ccc);">
Scroll down to test throttling!
</div>
- 如图所示:
2. 将节流函数封装为测试场景的一部分:
// 测试用节流函数
function throttle(func, limit) {
let lastCall = 0;
return function (...args) {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
func.apply(this, args);
}
};
}
// 滚动事件测试
let callCount = 0; // 记录调用次数
function logScroll() {
callCount++;
console.log('Scroll event triggered:', callCount, 'times');
}
window.addEventListener('scroll', throttle(logScroll, 200));
3. 打开浏览器开发者工具,观察控制台
- 快速滚动页面,查看日志输出频率是否每隔 200 毫秒触发一次。
防抖 (Debounce)
- 延迟函数执行,直到事件停止触发一定时间,适用于 用户输入、搜索建议等场景。
实践示例:验证防抖功能是否正常工作
测试环境准备
1. 在页面上添加一个输入框
<input id="search" type="text" placeholder="请输入内容,测试防抖效果" />
页面效果
2. 将防抖逻辑与输入框事件结合
// 防抖函数
function debounce(func, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), delay);
};
}
// 输入事件绑定
const input = document.getElementById('search');
let callCount = 0; // 用于记录调用次数
input.addEventListener(
'input',
debounce(() => {
callCount++;
console.log('Debounced input event:', callCount);
}, 300)
);
3. 交互测试
- 快速输入内容,观察日志输出是否延迟 300ms。
- 停止输入后,是否只触发最后一次的事件。
总结与建议
- 优先解决重绘和重排问题,减少 DOM 操作和不必要的样式计算。
- 灵活使用节流和防抖,优化高频事件的性能开销。
- 充分利用 DevTools 和 Lighthouse,定位性能瓶颈并持续改进。
- 代码优化是一项持续工作,通过工具与最佳实践结合,保持页面性能稳定。
在线工具
- CodePen 如果有特定优化场景需要探讨或其他问题,随时提问!