永远不要过早优化代码
过早优化可能导致代码可读性下降,增加前期开发时间。当程序出现性能问题时再进行优化,可以更有效地解决实际问题。优化应根据具体情况灵活应对,针对不同的性能瓶颈采取相应措施。
使用 Key
在使用 v-for
生成列表时,为每个列表项分配一个稳定且唯一的 key
,可以减少 Vue 在列表变动时的重新渲染,提高渲染效率。
使用冻结对象
当对象数量众多且结构复杂时,Vue 的响应式系统需要频繁遍历这些对象,增加性能开销。通过冻结对象,可以避免 Vue 遍历这些对象,从而提升性能。
不需要遍历的场景
如果对象仅用于展示,不需要动态修改,可以使用冻结对象。冻结后的对象不会被 Vue 监测为响应式,减少了性能开销。
const dataObject = {
a: 1,
b: 2,
};
Object.freeze(dataObject);
console.log(Object.isFrozen(dataObject)); // true
使用函数式组件
为什么函数组件性能优于普通组件
函数式组件由于其无状态和无实例的特性,相较于普通组件具有更高的渲染性能。具体原因包括:
函数式组件不包含生命周期钩子,减少了渲染过程中的方法调用。不使用响应式数据或计算属性,降低了响应式系统的负担。直接返回虚拟节点树,避免了实例化和垃圾回收的开销。结构简单,虚拟 DOM 的差异化和渲染更迅速。
使用计算属性
计算属性可以缓存计算结果,避免重复计算,提升性能。
非实时绑定的表单项
使用 v-model
进行实时数据绑定会在用户每次修改表单项时触发 Vue 的重新渲染。为减少性能开销,可以使用 v-model.lazy
或其他非实时绑定方式,但需注意数据与表单项的值可能在短时间内不同步。
保持对象引用稳定
Vue 在数据变化时触发渲染。保持依赖数据的引用稳定,可以避免不必要的重新渲染。
function hasChanged(x, y) {
if (x === y) {
return x === 0 && 1 / x !== 1 / y;
} else {
return x === x || y === y;
}
}
确保组件依赖的数据不变,可以避免组件重新渲染。对于原始数据类型,保持其值不变。对于对象类型,保持其引用不变。通过细分组件,保持属性引用稳定,避免子组件的多余渲染。
实际案例
通过远程接口获取评论时,每次获取全部列表会生成新的引用,影响性能。改为获取部分数据并推送到列表中,可以复用之前的引用,提高渲染速度。
延迟装载
在 JavaScript 中,延迟装载(懒加载)用于提升页面加载速度和性能,尤其在处理大量数据或资源时。以下是几种实现方法:
使用 async
和 defer
属性控制脚本加载时机。
<script async src="path/to/your/script.js"></script>
<script defer src="path/to/your/script.js"></script>
图片懒加载,使用 loading="lazy"
属性。
<img src="image.jpg" alt="Description" loading="lazy" />
利用 Intersection Observer API 延迟加载任意元素。
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 加载内容,如图片或脚本
}
});
});
// 观察特定元素的可见性
observer.observe(document.querySelector('.some-element'));
动态导入模块,实现代码分割和懒加载。
// 仅在需要时加载模块
const module = await import('./module.js');
使用第三方库(如 lazysizes)处理更复杂的懒加载需求。
延迟渲染
requestAnimationFrame
requestAnimationFrame
是浏览器的 API,用于在下一次重绘前执行回调函数,适用于高效、流畅的动画和页面渲染调整。常见使用场景包括:
动画:推荐使用 requestAnimationFrame
进行 CSS、canvas 或 WebGL 动画,确保平滑帧率。滚动效果:实现自定义滚动效果或监听滚动事件时,使用 requestAnimationFrame
提高处理效率。节流和去抖:处理高频率事件(如 mousemove
或 resize
)时,使用 requestAnimationFrame
限制事件处理频率,提升性能。页面元素渲染和调整:在 JavaScript 中更改元素样式或布局时,使用 requestAnimationFrame
安排更改,使其平滑高效。游戏循环:在浏览器中运行的游戏使用 requestAnimationFrame
实现主循环,与浏览器的重绘过程同步。
requestAnimationFrame
的优势在于与浏览器的帧刷新率同步(通常为 60fps),提供流畅体验;标签页不在前台时自动暂停,节省资源。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>requestAnimationFrame 示例</title>
<style>
#box {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
top: 50%;
left: 0;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById('box');
let leftPosition = 0;
function moveBox() {
leftPosition += 2;
box.style.left = leftPosition + 'px';
if (leftPosition < window.innerWidth) {
requestAnimationFrame(moveBox);
}
}
requestAnimationFrame(moveBox);
</script>
</body>
</html>
上述 moveBox
函数在每一帧调用,使动画持续进行。
Vue 优化组件加载
在渲染大量组件时,通过延迟加载可以提升性能。
export default function (maxFrameCount) {
return {
data() {
return {
frameCount: 0, // 当前帧计数
};
},
mounted() {
const updateFrameCount = () => {
requestAnimationFrame(() => {
this.frameCount++;
if (this.frameCount < maxFrameCount) {
updateFrameCount();
}
});
};
updateFrameCount();
},
methods: {
defer(showInFrameCount) {
return this.frameCount >= showInFrameCount;
},
},
};
}
该函数通过 requestAnimationFrame
更新帧计数,控制内容的延迟显示或渲染,适用于需要分帧加载大量组件的场景。
注意
确保在优化过程中不改变使用的包版本,针对当前版本进行优化。同时,适当优化变量名,使其更具可读性和语义化。