前端性能优化

前端性能优化

前端性能优化

前端性能优化是一个涉及多个方面的复杂过程,旨在提高网页加载速度、减少资源消耗、提升用户体验。以下是一些常见的前端性能优化策略:

  1. 减少HTTP请求
    • 合并文件(如CSS和JavaScript文件)以减少请求次数。
    • 使用CSS Sprites技术合并图片,减少图片请求。
  2. 压缩资源文件
    • 压缩CSS、JavaScript和HTML文件,减少文件大小。
    • 压缩图片文件,使用WebP等现代格式。
  3. 使用CDN
    • 通过内容分发网络(CDN)加速资源加载,特别是对于静态资源。
  4. 浏览器缓存
    • 利用HTTP缓存控制,使得重复访问的资源可以直接从本地缓存加载。
  5. 代码分割
    • 使用模块化和代码分割技术,按需加载资源。
  6. 异步加载非关键资源
    • 使用异步或延迟加载技术加载非首屏资源。
  7. 优化CSS和JavaScript
    • 减少复杂的CSS选择器和JavaScript的DOM操作。
    • 避免使用过多的全局变量和闭包。
  8. 减少重绘和重排
    • 优化CSS和DOM结构,减少浏览器的重绘(repaint)和重排(reflow)。
  9. 使用服务端渲染(SSR)或静态站点生成(SSG)
    • 提升首屏加载速度,改善SEO。
  10. 优化字体加载
    • 使用font-display属性控制字体的加载行为,避免字体加载导致的文本不可见。
  11. 使用Web字体优化技术
    • 仅加载所需的字体变体和字符集。
  12. 优化第三方脚本和插件
    • 审查和监控第三方脚本的性能影响,避免不必要的加载。
  13. 使用预加载和预连接
    • 使用<link rel="preload">预加载关键资源,使用<link rel="preconnect">预连接重要的域名。
  14. 优化首字节时间(TTFB)
    • 减少服务器响应时间,优化后端性能。
  15. 使用HTTP/2或HTTP/3
    • 利用新的HTTP协议特性,如多路复用,减少连接开销。
  16. 移动性能优化
    • 优化触摸事件处理,减少内存使用,优化渲染性能。
  17. 性能预算
    • 为网站设定性能预算,确保新添加的功能不会使网站变得臃肿。
  18. 性能监测和分析
    • 使用工具如Lighthouse、PageSpeed Insights等定期检查网站性能,并根据反馈进行优化。
  19. 使用Web Workers
    • 对于复杂的计算任务,使用Web Workers在后台线程中运行,避免阻塞主线程。
  20. 懒加载图片和视频
    • 仅在用户滚动到相关内容时才加载图片和视频。
      性能优化是一个持续的过程,需要不断地测试、分析和调整。通过实施上述策略,可以显著提升网站的性能和用户体验。

重绘重排

在Web开发中,重绘(Repaint)和重排(Reflow)是两个重要的性能优化概念。它们指的是浏览器在处理DOM(文档对象模型)时发生的两种不同的操作:

重排(Reflow)

重排是指浏览器重新计算元素的位置和尺寸的过程。当DOM结构发生变化时,如元素的添加、删除、移动或者样式的改变(比如改变宽度、高度、隐藏等),浏览器需要重新计算元素的几何属性(位置和尺寸),这个过程称为重排。
触发重排的操作:

  • 元素的尺寸、位置或内容发生变化。
  • 元素的字体大小、行高、外边距、内边距等属性改变。
  • 页面加载时的初始渲染。
  • 浏览器窗口尺寸改变(例如,用户调整浏览器窗口大小)。
    减少重排的策略:
  • 减少DOM操作,尤其是批量操作,可以使用DocumentFragment来减少重排次数。
  • 使用transformopacity属性进行动画,因为它们不会引起重排。
  • 避免使用table布局,因为表格布局的重排成本较高。
  • 使用CSS的will-change属性来提示浏览器哪些属性可能会变化。

重绘(Repaint)

重绘是指在元素的几何属性没有变化,但是元素的外观(如颜色、阴影、边框颜色等)发生变化时,浏览器需要重新绘制元素以反映这些变化的过程。
触发重绘的操作:

  • 元素的颜色、阴影、边框颜色等属性改变。
  • 元素的visibility属性从hidden变为visible
  • 元素的background属性改变。
    减少重绘的策略:
  • 减少不必要的颜色和外观属性的改变。
  • 使用CSS的will-change属性来提示浏览器哪些属性可能会变化。

性能影响

  • 重排通常比重绘更消耗性能,因为它涉及到计算元素的几何属性,而重绘只需要更新元素的视觉表现。
  • 重排和重绘经常一起发生,因为改变元素的几何属性通常会导致外观变化。
  • 避免频繁的重排和重绘是提高网页性能的关键,特别是在复杂的页面和动画效果中。

性能优化

为了提高性能,开发者应该尽量减少重排和重绘的发生次数,以及减少每次重排和重绘的成本。这可以通过优化CSS和JavaScript代码,合理使用CSS属性,以及利用现代浏览器提供的API来实现。

前端阻止在一定时间内多次发送网络请求

在前端开发中,阻止在一定时间内多次发送网络请求可以通过以下几种方法实现:

1. 使用请求节流(Throttling)

请求节流是一种限制函数执行频率的技术,确保函数在指定的时间间隔内最多只执行一次。这可以通过封装请求函数来实现,例如使用高阶函数来包装原始的请求函数,增加一个时间戳来判断是否在指定的时间间隔内已经发送过请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function throttleRequest(func, limit) {
let lastFunc;
let lastRan;
return function() {
const context = this;
const args = arguments;
if (!lastRan) {
func.apply(context, args);
lastRan = Date.now();
} else {
clearTimeout(lastFunc);
lastFunc = setTimeout(function() {
if ((Date.now() - lastRan) >= limit) {
func.apply(context, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
}
}
// 使用
const throttledFetch = throttleRequest(fetchData, 1000); // 1000毫秒内最多执行一次

2. 使用请求防抖(Debouncing)

请求防抖是一种确保函数在事件触发后等待一定延迟时间才执行的技术,如果在这段时间内再次触发事件,则重新计算延迟时间。这对于处理连续的事件(如输入框的input事件或窗口的scroll事件)特别有用。

1
2
3
4
5
6
7
8
9
10
11
function debounceRequest(func, delay) {
let inDebounce;
return function() {
const context = this;
const args = arguments;
clearTimeout(inDebounce);
inDebounce = setTimeout(() => func.apply(context, args), delay);
}
}
// 使用
const debouncedFetch = debounceRequest(fetchData, 1000); // 触发事件后等待1000毫秒才执行

3. 取消重复的网络请求

如果你使用的是axios这样的库,可以通过拦截器来取消重复的请求。你可以存储所有正在进行的请求,并在发送新请求之前检查是否有重复的请求,如果有,则取消之前的请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
let pendingRequests = new Map();
axios.interceptors.request.use(config => {
const requestKey = `${config.url}-${config.method}`;
if (pendingRequests.has(requestKey)) {
pendingRequests.get(requestKey).cancel('Another request has been made');
}
const cancelToken = new axios.CancelToken(cancel => {
pendingRequests.set(requestKey, { cancel });
});
config.cancelToken = cancelToken;
return config;
}, error => {
return Promise.reject(error);
});
axios.interceptors.response.use(response => {
const requestKey = `${response.config.url}-${response.config.method}`;
pendingRequests.delete(requestKey);
return response;
}, error => {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
} else {
console.error('Error:', error);
}
return Promise.reject(error);
});

这些方法可以帮助你控制前端在一定时间内发送网络请求的频率,从而提高应用的性能和用户体验。

防抖详解

防抖(Debouncing)是一种在前端开发中常用的性能优化技术,特别适用于处理那些可能会被频繁触发的事件,如输入框的input事件、窗口的resize事件、滚动条的scroll事件等。防抖的核心思想是:在事件被触发后等待一定的延迟时间,如果在这段延迟时间内事件又被重新触发,则重新开始计算延迟时间。只有当指定的延迟时间内没有再次触发事件时,才会执行相应的回调函数。

防抖的工作原理

  1. 事件触发:当事件首次被触发时,防抖函数会设置一个延迟执行的回调函数。
  2. 延迟等待:如果在设定的延迟时间内事件再次被触发,防抖函数会取消之前的延迟执行,并重新设置一个新的延迟。
  3. 执行回调:只有当延迟时间结束后没有再次触发事件,才会执行回调函数。

防抖的应用场景

  • 输入验证:在用户输入时,不需要对每次输入都进行验证,而是在用户停止输入一段时间后再进行验证。
  • 搜索建议:在用户输入搜索关键词时,不需要对每次输入都发送请求获取搜索建议,而是在用户停止输入一段时间后再发送请求。
  • 窗口调整大小:在用户调整浏览器窗口大小时,不需要对每次调整都进行响应,而是在用户停止调整一段时间后再进行响应。
  • 滚动事件处理:在用户滚动页面时,不需要对每次滚动都进行处理,而是在用户停止滚动一段时间后再进行处理。

实现防抖函数

下面是一个简单的防抖函数的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 创建一个防抖函数
* @param func 需要防抖的函数
* @param wait 延迟时间,单位为毫秒
* @param immediate 是否立即执行一次(在等待期间没有再次触发事件时)
*/
function debounce(func, wait, immediate = false) {
let timeout;
return function() {
const context = this;
const args = arguments;
const later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
// 使用示例
const myDebouncedFunction = debounce(() => {
console.log('Function debounced!');
}, 2000);
window.addEventListener('resize', myDebouncedFunction);

在这个例子中,debounce函数接受三个参数:需要防抖的函数func、延迟时间wait(以毫秒为单位),以及一个可选参数immediate,用于控制是否在延迟开始前立即执行一次回调函数。

注意事项

  • 选择适当的延迟时间:延迟时间的选择取决于具体的应用场景,太短可能无法有效减少事件处理的频率,太长可能会影响用户体验。
  • 考虑是否需要立即执行:根据需求决定是否在事件首次触发时立即执行回调函数。
  • 内存泄漏:确保在组件卸载或不再需要时清除定时器,避免内存泄漏。
    通过合理使用防抖技术,可以显著提高应用的性能,尤其是在处理高频事件时。