225 lines
6.9 KiB
JavaScript
225 lines
6.9 KiB
JavaScript
/**
|
||
* Paper Burner - 性能优化配置
|
||
* Phase 3.5: 统一管理所有性能相关的配置常量
|
||
* Phase 4.4: 设备自适应配置 + 基础 A/B 测试框架
|
||
*/
|
||
|
||
/**
|
||
* 设备性能检测
|
||
* - 基于 navigator.deviceMemory 与 navigator.hardwareConcurrency
|
||
* - 返回 'high' | 'medium' | 'low'
|
||
*/
|
||
function detectDevicePerformance() {
|
||
try {
|
||
var nav = window.navigator || {};
|
||
var memory = typeof nav.deviceMemory === 'number' ? nav.deviceMemory : 4; // 默认按中等设备处理
|
||
var cores = typeof nav.hardwareConcurrency === 'number' ? nav.hardwareConcurrency : 4;
|
||
|
||
if (memory >= 8 && cores >= 8) return 'high';
|
||
if (memory >= 4 && cores >= 4) return 'medium';
|
||
return 'low';
|
||
} catch (e) {
|
||
return 'medium';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Phase 4.4 - 性能实验配置
|
||
* - 使用 localStorage('perf_variant') 控制实验分组
|
||
* - 默认分组为 'control',保持与当前行为尽量接近
|
||
* - 实验分组可通过控制台手动切换:PerformanceExperiment.setVariant('variant_a')
|
||
*/
|
||
window.PerformanceExperiment = (function() {
|
||
var STORAGE_KEY = 'perf_variant';
|
||
var variant = 'control';
|
||
|
||
try {
|
||
var saved = window.localStorage ? window.localStorage.getItem(STORAGE_KEY) : null;
|
||
if (saved === 'control' || saved === 'variant_a' || saved === 'variant_b') {
|
||
variant = saved;
|
||
}
|
||
} catch (e) {
|
||
// 本地存储不可用时,保持默认值 'control'
|
||
}
|
||
|
||
var deviceTier = detectDevicePerformance();
|
||
|
||
return {
|
||
storageKey: STORAGE_KEY,
|
||
variant: variant,
|
||
deviceTier: deviceTier,
|
||
|
||
setVariant: function(nextVariant) {
|
||
if (nextVariant !== 'control' && nextVariant !== 'variant_a' && nextVariant !== 'variant_b') return;
|
||
this.variant = nextVariant;
|
||
try {
|
||
if (window.localStorage) {
|
||
window.localStorage.setItem(STORAGE_KEY, nextVariant);
|
||
}
|
||
} catch (e) {
|
||
// 忽略本地存储错误
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 获取当前分组下的配置覆盖项
|
||
* key 示例:'UPDATE_INTERVALS'
|
||
*/
|
||
getConfig: function(key) {
|
||
var variants = {
|
||
control: {
|
||
UPDATE_INTERVALS: { FOREGROUND: 400, DEBOUNCE: 100 }
|
||
},
|
||
// 更激进:更快的前台更新 + 更短防抖
|
||
variant_a: {
|
||
UPDATE_INTERVALS: { FOREGROUND: 300, DEBOUNCE: 80 }
|
||
},
|
||
// 更保守:更慢的前台更新 + 更长防抖
|
||
variant_b: {
|
||
UPDATE_INTERVALS: { FOREGROUND: 500, DEBOUNCE: 120 }
|
||
}
|
||
};
|
||
var group = variants[this.variant] || variants.control;
|
||
return group[key];
|
||
}
|
||
};
|
||
})();
|
||
|
||
// 设备自适应基线配置(在实验覆盖前计算)
|
||
var __pbDeviceTier = window.PerformanceExperiment && window.PerformanceExperiment.deviceTier
|
||
? window.PerformanceExperiment.deviceTier
|
||
: detectDevicePerformance();
|
||
|
||
// 基线更新间隔(未应用 A/B 实验前)
|
||
var __pbBaseForegroundInterval = __pbDeviceTier === 'high' ? 300 : 400;
|
||
var __pbBaseDebounce = 100;
|
||
|
||
// 应用 A/B 实验覆盖(仅限 UPDATE_INTERVALS)
|
||
var __pbExperimentIntervals = window.PerformanceExperiment && typeof window.PerformanceExperiment.getConfig === 'function'
|
||
? window.PerformanceExperiment.getConfig('UPDATE_INTERVALS')
|
||
: null;
|
||
|
||
if (__pbExperimentIntervals) {
|
||
if (typeof __pbExperimentIntervals.FOREGROUND === 'number') {
|
||
__pbBaseForegroundInterval = __pbExperimentIntervals.FOREGROUND;
|
||
}
|
||
if (typeof __pbExperimentIntervals.DEBOUNCE === 'number') {
|
||
__pbBaseDebounce = __pbExperimentIntervals.DEBOUNCE;
|
||
}
|
||
}
|
||
|
||
window.PerformanceConfig = {
|
||
// 流式更新间隔配置(设备自适应 + A/B 覆盖)
|
||
UPDATE_INTERVALS: {
|
||
FOREGROUND: __pbBaseForegroundInterval, // 前台标签页更新间隔 (ms)
|
||
BACKGROUND: 1500, // 后台标签页更新间隔 (ms)
|
||
DEBOUNCE: __pbBaseDebounce // 防抖延迟 (ms)
|
||
},
|
||
|
||
// 智能跳帧配置(根据设备性能调整阈值与最大倍数)
|
||
ADAPTIVE_RENDER: {
|
||
HEAVY_THRESHOLD: (function() {
|
||
// 高核机器允许更高的“重渲染”阈值
|
||
try {
|
||
var cores = typeof window.navigator?.hardwareConcurrency === 'number'
|
||
? window.navigator.hardwareConcurrency
|
||
: 4;
|
||
return cores > 4 ? 300 : 200;
|
||
} catch (e) {
|
||
return 200;
|
||
}
|
||
})(),
|
||
MIN_MULTIPLIER: 1,
|
||
MAX_MULTIPLIER: __pbDeviceTier === 'low' ? 8 : 4,
|
||
DECAY_THRESHOLD: 100, // 衰减阈值 (ms) - 低于此值时逐步恢复
|
||
WARN_THRESHOLD: 400 // 日志警告阈值 (ms,用于性能日志)
|
||
},
|
||
|
||
// PNG导出配置
|
||
EXPORT: {
|
||
MAX_WIDTH: 1200, // 导出容器最大宽度 (px)
|
||
ABSOLUTE_MAX_WIDTH: 2000, // 绝对最大宽度 (px)
|
||
LAYOUT_DELAY: 50, // DOM重排延迟 (ms)
|
||
SCALE: 2 // html2canvas缩放倍数
|
||
},
|
||
|
||
// 日志配置
|
||
LOGGING: {
|
||
ENABLED: true, // 是否启用日志
|
||
LEVEL: 'warn', // 日志级别: 'debug' | 'info' | 'warn' | 'error'
|
||
PERFORMANCE_LOGS: true, // 是否启用性能日志
|
||
PERF_MIN_INTERVAL_MS: 2000 // 性能日志最小间隔,避免控制台被刷屏
|
||
},
|
||
|
||
// 滚动配置
|
||
SCROLL: {
|
||
BOTTOM_THRESHOLD: 50 // 判定用户在底部的容差 (px)
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 日志工具 - 根据配置级别输出日志
|
||
*/
|
||
window.PerfLogger = {
|
||
_shouldLog(level) {
|
||
if (!window.PerformanceConfig.LOGGING.ENABLED) return false;
|
||
|
||
const levels = { debug: 0, info: 1, warn: 2, error: 3 };
|
||
const configLevel = levels[window.PerformanceConfig.LOGGING.LEVEL] || 1;
|
||
const currentLevel = levels[level] || 0;
|
||
|
||
return currentLevel >= configLevel;
|
||
},
|
||
|
||
debug(...args) {
|
||
if (this._shouldLog('debug')) console.log('[Phase 3.5 Debug]', ...args);
|
||
},
|
||
|
||
info(...args) {
|
||
if (this._shouldLog('info')) console.log('[Phase 3.5 Info]', ...args);
|
||
},
|
||
|
||
warn(...args) {
|
||
if (this._shouldLog('warn')) console.warn('[Phase 3.5 Warn]', ...args);
|
||
},
|
||
|
||
error(...args) {
|
||
if (this._shouldLog('error')) console.error('[Phase 3.5 Error]', ...args);
|
||
},
|
||
|
||
perf(message, duration) {
|
||
if (!window.PerformanceConfig.LOGGING.PERFORMANCE_LOGS) return;
|
||
if (duration <= window.PerformanceConfig.ADAPTIVE_RENDER.WARN_THRESHOLD) return;
|
||
|
||
// 限制性能日志频率,避免在流式场景中产生成千上万条 warning
|
||
const minInterval = window.PerformanceConfig.LOGGING.PERF_MIN_INTERVAL_MS || 2000;
|
||
const now = (typeof performance !== 'undefined' && typeof performance.now === 'function')
|
||
? performance.now()
|
||
: Date.now();
|
||
|
||
if (this._perfLastLogTime && (now - this._perfLastLogTime) < minInterval) {
|
||
return;
|
||
}
|
||
|
||
this._perfLastLogTime = now;
|
||
this.warn(`性能: ${message} - ${duration.toFixed(0)}ms`);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 渲染状态管理 - 避免全局变量污染
|
||
*/
|
||
window.ChatbotRenderState = {
|
||
lastRenderedMessageCount: 0,
|
||
isExporting: false,
|
||
adaptiveMultiplier: 1,
|
||
lastRenderDuration: 0,
|
||
|
||
reset() {
|
||
this.lastRenderedMessageCount = 0;
|
||
this.isExporting = false;
|
||
this.adaptiveMultiplier = 1;
|
||
this.lastRenderDuration = 0;
|
||
}
|
||
};
|