feat: 创建性能阈值配置
This commit is contained in:
306
src/constants/performanceThresholds.js
Normal file
306
src/constants/performanceThresholds.js
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/**
|
||||||
|
* 性能指标阈值配置
|
||||||
|
* 基于 Google Web Vitals 标准和项目实际情况
|
||||||
|
*
|
||||||
|
* 评级标准:
|
||||||
|
* - good: 绿色,性能优秀
|
||||||
|
* - needs-improvement: 黄色,需要改进
|
||||||
|
* - poor: 红色,性能较差
|
||||||
|
*
|
||||||
|
* @see https://web.dev/defining-core-web-vitals-thresholds/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Web Vitals 官方阈值(Google 标准)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Largest Contentful Paint (LCP) - 最大内容绘制
|
||||||
|
* 衡量加载性能,理想情况下应在 2.5 秒内完成
|
||||||
|
*/
|
||||||
|
export const LCP_THRESHOLDS = {
|
||||||
|
good: 2500, // < 2.5s 为优秀
|
||||||
|
needsImprovement: 4000, // 2.5s - 4s 需要改进
|
||||||
|
// > 4s 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First Contentful Paint (FCP) - 首次内容绘制
|
||||||
|
* 衡量首次渲染任何内容的速度
|
||||||
|
*/
|
||||||
|
export const FCP_THRESHOLDS = {
|
||||||
|
good: 1800, // < 1.8s 为优秀
|
||||||
|
needsImprovement: 3000, // 1.8s - 3s 需要改进
|
||||||
|
// > 3s 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cumulative Layout Shift (CLS) - 累积布局偏移
|
||||||
|
* 衡量视觉稳定性(无单位,分数值)
|
||||||
|
*/
|
||||||
|
export const CLS_THRESHOLDS = {
|
||||||
|
good: 0.1, // < 0.1 为优秀
|
||||||
|
needsImprovement: 0.25, // 0.1 - 0.25 需要改进
|
||||||
|
// > 0.25 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First Input Delay (FID) - 首次输入延迟
|
||||||
|
* 衡量交互性能
|
||||||
|
*/
|
||||||
|
export const FID_THRESHOLDS = {
|
||||||
|
good: 100, // < 100ms 为优秀
|
||||||
|
needsImprovement: 300, // 100ms - 300ms 需要改进
|
||||||
|
// > 300ms 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to First Byte (TTFB) - 首字节时间
|
||||||
|
* 衡量服务器响应速度
|
||||||
|
*/
|
||||||
|
export const TTFB_THRESHOLDS = {
|
||||||
|
good: 800, // < 0.8s 为优秀
|
||||||
|
needsImprovement: 1800, // 0.8s - 1.8s 需要改进
|
||||||
|
// > 1.8s 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 自定义指标阈值(项目特定)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to Interactive (TTI) - 首屏可交互时间
|
||||||
|
* 自定义指标:从页面加载到用户可以交互的时间
|
||||||
|
*/
|
||||||
|
export const TTI_THRESHOLDS = {
|
||||||
|
good: 3500, // < 3.5s 为优秀
|
||||||
|
needsImprovement: 7300, // 3.5s - 7.3s 需要改进
|
||||||
|
// > 7.3s 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 骨架屏展示时长阈值
|
||||||
|
*/
|
||||||
|
export const SKELETON_DURATION_THRESHOLDS = {
|
||||||
|
good: 300, // < 0.3s 为优秀(骨架屏展示时间短)
|
||||||
|
needsImprovement: 1000, // 0.3s - 1s 需要改进
|
||||||
|
// > 1s 为较差(骨架屏展示太久)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 响应时间阈值
|
||||||
|
*/
|
||||||
|
export const API_RESPONSE_TIME_THRESHOLDS = {
|
||||||
|
good: 500, // < 500ms 为优秀
|
||||||
|
needsImprovement: 1500, // 500ms - 1.5s 需要改进
|
||||||
|
// > 1.5s 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源加载时间阈值
|
||||||
|
*/
|
||||||
|
export const RESOURCE_LOAD_TIME_THRESHOLDS = {
|
||||||
|
good: 2000, // < 2s 为优秀
|
||||||
|
needsImprovement: 5000, // 2s - 5s 需要改进
|
||||||
|
// > 5s 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundle 大小阈值(KB)
|
||||||
|
*/
|
||||||
|
export const BUNDLE_SIZE_THRESHOLDS = {
|
||||||
|
js: {
|
||||||
|
good: 500, // < 500KB 为优秀
|
||||||
|
needsImprovement: 1000, // 500KB - 1MB 需要改进
|
||||||
|
// > 1MB 为较差
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
good: 100, // < 100KB 为优秀
|
||||||
|
needsImprovement: 200, // 100KB - 200KB 需要改进
|
||||||
|
// > 200KB 为较差
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
good: 1500, // < 1.5MB 为优秀
|
||||||
|
needsImprovement: 3000, // 1.5MB - 3MB 需要改进
|
||||||
|
// > 3MB 为较差
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存命中率阈值(百分比)
|
||||||
|
*/
|
||||||
|
export const CACHE_HIT_RATE_THRESHOLDS = {
|
||||||
|
good: 80, // > 80% 为优秀
|
||||||
|
needsImprovement: 50, // 50% - 80% 需要改进
|
||||||
|
// < 50% 为较差
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 综合阈值配置对象
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有性能指标的阈值配置(用于类型化访问)
|
||||||
|
*/
|
||||||
|
export const PERFORMANCE_THRESHOLDS = {
|
||||||
|
LCP: LCP_THRESHOLDS,
|
||||||
|
FCP: FCP_THRESHOLDS,
|
||||||
|
CLS: CLS_THRESHOLDS,
|
||||||
|
FID: FID_THRESHOLDS,
|
||||||
|
TTFB: TTFB_THRESHOLDS,
|
||||||
|
TTI: TTI_THRESHOLDS,
|
||||||
|
SKELETON_DURATION: SKELETON_DURATION_THRESHOLDS,
|
||||||
|
API_RESPONSE_TIME: API_RESPONSE_TIME_THRESHOLDS,
|
||||||
|
RESOURCE_LOAD_TIME: RESOURCE_LOAD_TIME_THRESHOLDS,
|
||||||
|
BUNDLE_SIZE: BUNDLE_SIZE_THRESHOLDS,
|
||||||
|
CACHE_HIT_RATE: CACHE_HIT_RATE_THRESHOLDS,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 工具函数
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据指标值和阈值计算评级
|
||||||
|
* @param {number} value - 指标值
|
||||||
|
* @param {Object} thresholds - 阈值配置对象 { good, needsImprovement }
|
||||||
|
* @param {boolean} reverse - 是否反向评级(值越大越好,如缓存命中率)
|
||||||
|
* @returns {'good' | 'needs-improvement' | 'poor'}
|
||||||
|
*/
|
||||||
|
export const calculateRating = (value, thresholds, reverse = false) => {
|
||||||
|
if (!thresholds || typeof value !== 'number') {
|
||||||
|
return 'poor';
|
||||||
|
}
|
||||||
|
|
||||||
|
const { good, needsImprovement } = thresholds;
|
||||||
|
|
||||||
|
if (reverse) {
|
||||||
|
// 反向评级:值越大越好(如缓存命中率)
|
||||||
|
if (value >= good) return 'good';
|
||||||
|
if (value >= needsImprovement) return 'needs-improvement';
|
||||||
|
return 'poor';
|
||||||
|
} else {
|
||||||
|
// 正常评级:值越小越好(如加载时间)
|
||||||
|
if (value <= good) return 'good';
|
||||||
|
if (value <= needsImprovement) return 'needs-improvement';
|
||||||
|
return 'poor';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取评级对应的颜色(Chakra UI 颜色方案)
|
||||||
|
* @param {'good' | 'needs-improvement' | 'poor'} rating
|
||||||
|
* @returns {string} Chakra UI 颜色名称
|
||||||
|
*/
|
||||||
|
export const getRatingColor = (rating) => {
|
||||||
|
switch (rating) {
|
||||||
|
case 'good':
|
||||||
|
return 'green';
|
||||||
|
case 'needs-improvement':
|
||||||
|
return 'yellow';
|
||||||
|
case 'poor':
|
||||||
|
return 'red';
|
||||||
|
default:
|
||||||
|
return 'gray';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取评级对应的控制台颜色代码
|
||||||
|
* @param {'good' | 'needs-improvement' | 'poor'} rating
|
||||||
|
* @returns {string} ANSI 颜色代码
|
||||||
|
*/
|
||||||
|
export const getRatingConsoleColor = (rating) => {
|
||||||
|
switch (rating) {
|
||||||
|
case 'good':
|
||||||
|
return '\x1b[32m'; // 绿色
|
||||||
|
case 'needs-improvement':
|
||||||
|
return '\x1b[33m'; // 黄色
|
||||||
|
case 'poor':
|
||||||
|
return '\x1b[31m'; // 红色
|
||||||
|
default:
|
||||||
|
return '\x1b[0m'; // 重置
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取评级对应的图标
|
||||||
|
* @param {'good' | 'needs-improvement' | 'poor'} rating
|
||||||
|
* @returns {string} Emoji 图标
|
||||||
|
*/
|
||||||
|
export const getRatingIcon = (rating) => {
|
||||||
|
switch (rating) {
|
||||||
|
case 'good':
|
||||||
|
return '✅';
|
||||||
|
case 'needs-improvement':
|
||||||
|
return '⚠️';
|
||||||
|
case 'poor':
|
||||||
|
return '❌';
|
||||||
|
default:
|
||||||
|
return '❓';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化指标值(添加单位)
|
||||||
|
* @param {string} metricName - 指标名称
|
||||||
|
* @param {number} value - 指标值
|
||||||
|
* @returns {string} 格式化后的字符串
|
||||||
|
*/
|
||||||
|
export const formatMetricValue = (metricName, value) => {
|
||||||
|
if (typeof value !== 'number' || isNaN(value)) {
|
||||||
|
return 'N/A';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (metricName) {
|
||||||
|
case 'LCP':
|
||||||
|
case 'FCP':
|
||||||
|
case 'FID':
|
||||||
|
case 'TTFB':
|
||||||
|
case 'TTI':
|
||||||
|
case 'SKELETON_DURATION':
|
||||||
|
case 'API_RESPONSE_TIME':
|
||||||
|
case 'RESOURCE_LOAD_TIME':
|
||||||
|
// 时间类指标:转换为秒或毫秒
|
||||||
|
return value >= 1000
|
||||||
|
? `${(value / 1000).toFixed(2)}s`
|
||||||
|
: `${Math.round(value)}ms`;
|
||||||
|
|
||||||
|
case 'CLS':
|
||||||
|
// CLS 是无单位的分数
|
||||||
|
return value.toFixed(3);
|
||||||
|
|
||||||
|
case 'CACHE_HIT_RATE':
|
||||||
|
// 百分比
|
||||||
|
return `${value.toFixed(1)}%`;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// 默认保留两位小数
|
||||||
|
return value.toFixed(2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量计算所有 Web Vitals 指标的评级
|
||||||
|
* @param {Object} metrics - 指标对象 { LCP: value, FCP: value, ... }
|
||||||
|
* @returns {Object} 评级对象 { LCP: 'good', FCP: 'needs-improvement', ... }
|
||||||
|
*/
|
||||||
|
export const calculateAllRatings = (metrics) => {
|
||||||
|
const ratings = {};
|
||||||
|
|
||||||
|
Object.entries(metrics).forEach(([metricName, value]) => {
|
||||||
|
const thresholds = PERFORMANCE_THRESHOLDS[metricName];
|
||||||
|
if (thresholds) {
|
||||||
|
const isReverse = metricName === 'CACHE_HIT_RATE'; // 缓存命中率是反向评级
|
||||||
|
ratings[metricName] = calculateRating(value, thresholds, isReverse);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ratings;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 默认导出
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
export default PERFORMANCE_THRESHOLDS;
|
||||||
Reference in New Issue
Block a user