1. 减少重绘和重排
重绘(repaint)和重排(reflow),也就是布局更改,是页面渲染的两个重要阶段。当Dom的一部分需要更改或者页面的布局需要重新计算时,就会发生重排。重绘则是在页面的某些元素需要更新颜色、背景等,但不包括布局变化时发生。
可以减少重绘和重排的次数,来提高页面性能。来个例子:
```// 避免在一个循环中多次改变样式
for (let i = 0; i < elements.length; i++) {
elements[i].style.height = (i * 5) + 'px';
elements[i].style.width = (i * 10) + 'px';
}
可以使用requestAnimationFrame 来批量更新样式,减少重排的发生:
```requestAnimationFrame(() => {
for (let i = 0; i < elements.length; i++) {
elements[i].style.height = (i * 5) + 'px';
elements[i].style.width = (i * 10) + 'px';
}
});
- 需要修改 DOM 树外部样式,然后使用一次性操作将其应用到 DOM 中,以减少重排的次数。
- 使用 CSS 类名来修改批量样式,而不是直接操作单个元素的样式。
- 避免在循环中多次样式,可以使用
requestAnimationFrame或修改文档片段来批量处理修改。 2. 使用节流和防抖技术
防抖和节流都是为了限制函数的执行频率。防抖(debounce)是当调用动作n毫秒后,未再次调用动作,才会执行该动作;节流(throttle)是预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作。
例如,可能在一个在滚动事件中调用的函数。如果这个函数在每次滚动时都被调用,它可能会对性能产生重大影响。这个时候就可以使用防抖或节流来限制函数的执行频率:
```// 防抖
function debounce(func, wait = 100) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
window.addEventListener('scroll', debounce(function() {
console.log('Scrolling!');
}));
// 节流
function throttle(func, limit = 300) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
window.addEventListener('scroll', throttle(function() {
console.log('Scrolling!');
}));
- 针对间隙触发的事件(如滚动、调整窗口大小),使用节流和防来限制函数的执行频率,减少不必要的计算和操作。
- 防流可以保证只在事件触发后的一段时间内执行最后一次操作,而节流则可以限制在一定时间间隔内只执行一次操作。
3. 使用性能分析工具
Chrome的开发者工具和其他浏览器内置的工具包含了一系列的性能分析工具,可以帮助你发现哪些代码可能正在影响你的性能。有一说一,这个方法老占便宜了。简单又实惠,消耗时间还少。
例如,可以使用Chrome的Performance panel来记录和查看页面在一段时间内的性能情况。这个方法可以在你遇到瓶颈时用一用,可能突然一下灵感就来了。
```console.time('myFunction');
function myFunction() {
// 需要评估性能的代码
}
console.timeEnd('myFunction');
这将在控制台打印出函数执行所花费的时间,从而帮助你找到可能需要优化的部分。
- 使用浏览器的开发者工具(如 Chrome 的性能面板)来进行性能分析和调试。
- 通过性能分析工具,可以查看代码中的性能瓶颈、CPU使用情况、内存泄漏等问题,从而对缓存地进行优化。
4.使用文档片段(Document Fragments)
在通过 JavaScript 动态生成大量 DOM 元素时,直接将它们添加到页面上可能会导致性能下降。这是因为每次添加元素都会触发一次重排(回流)。
为了优化这个过程,可以使用文档片段(Document Fragments)。文档片段是一种轻量级的 DOM 节点容器,可以在其中构建 DOM 结构,然后将整个文本
以下<ul>列表<li>元素
```// 不推荐的写法
const list = document.getElementById('myList');
for (let i = 0; i < 1000; i++) {
const listItem = document.createElement('li');
listItem.textContent = '列表项 ' + i;
list.appendChild(listItem);
}
// 推荐的写法(使用文档片段)
const list = document.getElementById('myList');
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const listItem = document.createElement('li');
listItem.textContent = '列表项 ' + i;
fragment.appendChild(listItem);
}
list.appendChild(fragment);
除此之外还有一些小小的建议:
- 尽量减少不必要的循环、条件判断和函数调用,只执行必要的操作。
- 存储计算结果,避免重复计算相同的值。
- 避免重叠的 DOM 操作,尽量将多个操作合并为一次操作。
- 减少请求次数,合并和压缩文件,使用缓存等方法来减少网络负载。
- 使用异步加载和延迟加载来优化页面加载时间。
- 在处理大量数据时,选择适当的数据结构和算法可以显着提高代码的性能。
- 使用哈希表、集合、树等数据结构来快速查找、过滤和操作数据。