跳到主要内容

永远不要过早优化代码

过早优化可能导致代码可读性下降,增加前期开发时间。当程序出现性能问题时再进行优化,可以更有效地解决实际问题。优化应根据具体情况灵活应对,针对不同的性能瓶颈采取相应措施。

使用 Key

在使用 v-for 生成列表时,为每个列表项分配一个稳定且唯一的 key,可以减少 Vue 在列表变动时的重新渲染,提高渲染效率。

使用冻结对象

当对象数量众多且结构复杂时,Vue 的响应式系统需要频繁遍历这些对象,增加性能开销。通过冻结对象,可以避免 Vue 遍历这些对象,从而提升性能。

不需要遍历的场景

如果对象仅用于展示,不需要动态修改,可以使用冻结对象。冻结后的对象不会被 Vue 监测为响应式,减少了性能开销。

const dataObject = {
a: 1,
b: 2,
};

Object.freeze(dataObject);
console.log(Object.isFrozen(dataObject)); // true

使用函数式组件

渲染函数 & JSX | Vue.js

为什么函数组件性能优于普通组件

函数式组件由于其无状态和无实例的特性,相较于普通组件具有更高的渲染性能。具体原因包括:

函数式组件不包含生命周期钩子,减少了渲染过程中的方法调用。不使用响应式数据或计算属性,降低了响应式系统的负担。直接返回虚拟节点树,避免了实例化和垃圾回收的开销。结构简单,虚拟 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 中,延迟装载(懒加载)用于提升页面加载速度和性能,尤其在处理大量数据或资源时。以下是几种实现方法:

使用 asyncdefer 属性控制脚本加载时机。

<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 提高处理效率。节流和去抖:处理高频率事件(如 mousemoveresize)时,使用 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 更新帧计数,控制内容的延迟显示或渲染,适用于需要分帧加载大量组件的场景。

注意

确保在优化过程中不改变使用的包版本,针对当前版本进行优化。同时,适当优化变量名,使其更具可读性和语义化。

参考链接