一、减少重绘和重排
(一)理解重绘和重排
-
重排(Reflow)
-
定义:当 DOM 的几何属性(如宽、高、边距、位置等)发生变化时,浏览器需要重新计算元素的几何属性,并重新布局页面,这个过程称为重排。
-
常见触发重排的操作:
- 改变元素的尺寸:例如设置
width、height、margin、padding等属性。 - 改变元素的位置:例如设置
left、top、right、bottom等属性。 - 改变浏览器窗口大小或字体大小。
- 添加或删除 DOM 节点。
- 改变元素的尺寸:例如设置
-
-
重绘(Repaint)
-
定义:当元素的外观(如颜色、背景色等)发生改变,但不影响布局时,浏览器只需要重新绘制元素的外观,这个过程称为重绘。
-
常见触发重绘的操作:
- 改变元素的颜色:例如设置
color、background - color等属性。 - 改变元素的不透明度:例如设置
opacity属性。
- 改变元素的颜色:例如设置
-
(二)减少重绘和重排的策略
- 合并样式更改
-
示例:
-
不好的做法:
// 多次更改样式,会多次触发重排和重绘
element.style.width = '100px';
element.style.height = '100px';
element.style.backgroundColor = 'red';
-
好的做法:
// 使用CSS类名或一次性更改样式
element.className = 'new - class';
// 或者使用CSSOM的方式
var style = element.style;
style.cssText = 'width: 100px; height: 100px; background - color: red;';
- 将 DOM 操作离线处理
-
使用
DocumentFragment: -
示例:
// 创建DocumentFragment
var fragment = document.createDocumentFragment();
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
li.textContent = 'Item'+ i;
fragment.appendChild(li);
}
// 一次性将DocumentFragment中的内容添加到DOM中
document.getElementById('list').appendChild(fragment);
-
使用
display: none: -
示例:
// 先隐藏元素
element.style.display = 'none';
// 进行大量DOM操作
//...
// 操作完成后再显示元素
element.style.display = '';
- 避免频繁访问布局信息
- 不好的做法:
// 每次循环都获取元素的高度,会导致多次重排
for (var i = 0; i < 10; i++) {
var height = element.offsetHeight;
//...
}
-
好的做法:
// 先获取布局信息,再进行操作
var height = element.offsetHeight;
for (var i = 0; i < 10; i++) {
// 使用之前获取的高度
//...
}
二、使用节流和防抖技术
(一)节流(Throttle)
-
定义
- 节流是指在一定时间内,只允许函数执行一次。例如,在滚动事件中,如果不进行节流处理,函数可能会在短时间内被频繁调用,通过节流可以限制函数的调用频率。
-
实现示例
function throttle(func, delay) {
let timer = null;
return function() {
if (!timer) {
func.apply(this, arguments);
timer = setTimeout(() => {
timer = null;
}, delay);
}
};
}
// 使用示例
window.addEventListener('scroll', throttle(() => {
console.log('Scrolled');
}, 200));
(二)防抖(Debounce)
-
定义
- 防抖是指在事件被触发后,延迟一定时间再执行回调函数,如果在延迟时间内事件再次被触发,则重新计算延迟时间。常用于搜索框输入事件等,避免频繁发送请求。
-
实现示例
function debounce(func, delay) {
let timer = null;
return function() {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, arguments);
}, delay);
};
}
// 使用示例
var input = document.getElementById('search - input');
input.addEventListener('input', debounce(() => {
console.log('Search input:', input.value);
}, 300));
三、使用性能分析工具
(一)浏览器自带的性能工具
-
Chrome DevTools
-
Timeline(时间轴)
-
功能:可以记录和可视化页面加载过程中的各种事件,包括 JavaScript 执行、DOM 事件、布局和绘制等。通过时间轴可以发现性能瓶颈,例如长时间的脚本执行或频繁的重排重绘。
-
使用方法:
- 打开 Chrome 浏览器,按
F12打开开发者工具。 - 选择
Timeline选项卡。 - 点击
Record按钮开始记录,然后在页面上进行操作,操作完成后点击Stop按钮。 - 分析时间轴上的记录,查看耗时较长的操作。
- 打开 Chrome 浏览器,按
-
-
Performance(性能)
-
功能:提供更详细的性能分析,包括 CPU 使用率、内存占用等。可以对 JavaScript 函数进行采样分析,查看函数的执行时间和调用频率。
-
使用方法:
- 打开 Chrome 开发者工具,选择
Performance选项卡。 - 点击
Record按钮开始记录,进行页面操作后停止记录。 - 在分析结果中查看各种性能指标和函数调用情况。
- 打开 Chrome 开发者工具,选择
-
-
(二)第三方性能分析工具
-
Lighthouse
-
功能:是一个开源的自动化工具,用于改进网页的质量。它可以对页面的性能、可访问性、最佳实践、搜索引擎优化(SEO)等方面进行评估,并给出改进建议。
-
使用方法:
- 在 Chrome 浏览器中,打开开发者工具,选择
Lighthouse选项卡。 - 选择要分析的类别(如性能),然后点击
Generate report按钮。 - 根据报告中的建议进行优化。
- 在 Chrome 浏览器中,打开开发者工具,选择
-
-
WebPageTest
-
功能:是一个在线的网页性能测试工具,可以从多个地点和浏览器对网页进行测试,提供详细的性能指标和优化建议,包括页面加载时间、首次字节时间(TTFB)、渲染开始时间等。
-
使用方法:
-
访问
https://www.webpagetest.org/。 -
输入要测试的网址,选择测试地点、浏览器等参数。
-
点击
Start Test按钮,等待测试结果。 -
分析测试报告,根据建议进行优化。
-
-
通过以上这些 JavaScript 性能优化和调试技巧,可以有效地提高网页的性能,提升用户体验。