Files
ZhiQiXiaoYuan/utils/performance.js
ChuXun eaab9a762a 1
2025-10-19 20:28:31 +08:00

391 lines
6.8 KiB
JavaScript

/**
* 性能优化工具集
* 包含防抖、节流、懒加载、缓存等功能
*/
/**
* 防抖函数
* @param {Function} func 要执行的函数
* @param {Number} wait 延迟时间(毫秒)
* @param {Boolean} immediate 是否立即执行
*/
function debounce(func, wait = 300, immediate = false) {
let timeout
return function executedFunction(...args) {
const context = this
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)
}
}
/**
* 节流函数
* @param {Function} func 要执行的函数
* @param {Number} limit 时间限制(毫秒)
*/
function throttle(func, limit = 300) {
let inThrottle
return function(...args) {
const context = this
if (!inThrottle) {
func.apply(context, args)
inThrottle = true
setTimeout(() => inThrottle = false, limit)
}
}
}
/**
* 缓存管理器
*/
class CacheManager {
constructor() {
this.cache = new Map()
this.maxSize = 50 // 最大缓存数量
this.ttl = 5 * 60 * 1000 // 默认5分钟过期
}
/**
* 设置缓存
*/
set(key, value, ttl = this.ttl) {
if (this.cache.size >= this.maxSize) {
// 删除最早的缓存
const firstKey = this.cache.keys().next().value
this.cache.delete(firstKey)
}
this.cache.set(key, {
value,
expires: Date.now() + ttl
})
}
/**
* 获取缓存
*/
get(key) {
const item = this.cache.get(key)
if (!item) {
return null
}
if (Date.now() > item.expires) {
this.cache.delete(key)
return null
}
return item.value
}
/**
* 删除缓存
*/
delete(key) {
return this.cache.delete(key)
}
/**
* 清空缓存
*/
clear() {
this.cache.clear()
}
/**
* 获取缓存大小
*/
size() {
return this.cache.size
}
/**
* 清理过期缓存
*/
cleanup() {
const now = Date.now()
for (const [key, item] of this.cache.entries()) {
if (now > item.expires) {
this.cache.delete(key)
}
}
}
}
/**
* 图片懒加载管理器
*/
class LazyLoadManager {
constructor() {
this.observer = null
this.images = []
}
/**
* 初始化懒加载
*/
init(selector = '.lazy-image') {
if (!wx.createIntersectionObserver) {
console.warn('当前环境不支持IntersectionObserver')
return
}
this.observer = wx.createIntersectionObserver()
this.observer.relativeToViewport({ bottom: 100 })
this.observer.observe(selector, (res) => {
if (res.intersectionRatio > 0) {
this.loadImage(res.id)
}
})
}
/**
* 加载图片
*/
loadImage(id) {
const image = this.images.find(img => img.id === id)
if (image && !image.loaded) {
image.loaded = true
// 触发图片加载
if (image.callback) {
image.callback()
}
}
}
/**
* 添加图片
*/
addImage(id, callback) {
this.images.push({ id, loaded: false, callback })
}
/**
* 销毁
*/
destroy() {
if (this.observer) {
this.observer.disconnect()
}
}
}
/**
* 分页加载管理器
*/
class PaginationManager {
constructor(config = {}) {
this.pageSize = config.pageSize || 20
this.currentPage = 1
this.totalPages = 0
this.totalCount = 0
this.hasMore = true
this.loading = false
this.data = []
}
/**
* 加载下一页
*/
async loadMore(fetchFunction) {
if (this.loading || !this.hasMore) {
return null
}
this.loading = true
try {
const result = await fetchFunction(this.currentPage, this.pageSize)
this.data = [...this.data, ...result.data]
this.totalCount = result.total
this.totalPages = Math.ceil(result.total / this.pageSize)
this.hasMore = this.currentPage < this.totalPages
this.currentPage++
return result
} finally {
this.loading = false
}
}
/**
* 重置
*/
reset() {
this.currentPage = 1
this.totalPages = 0
this.totalCount = 0
this.hasMore = true
this.loading = false
this.data = []
}
/**
* 获取状态
*/
getState() {
return {
currentPage: this.currentPage,
totalPages: this.totalPages,
totalCount: this.totalCount,
hasMore: this.hasMore,
loading: this.loading,
dataLength: this.data.length
}
}
}
/**
* 性能监控器
*/
class PerformanceMonitor {
constructor() {
this.metrics = []
}
/**
* 开始监控
*/
start(name) {
return {
name,
startTime: Date.now(),
end: () => this.end(name, Date.now())
}
}
/**
* 结束监控
*/
end(name, startTime) {
const duration = Date.now() - startTime
this.metrics.push({
name,
duration,
timestamp: Date.now()
})
// 性能警告
if (duration > 1000) {
console.warn(`[性能警告] ${name} 耗时 ${duration}ms`)
}
return duration
}
/**
* 获取指标
*/
getMetrics(name) {
if (name) {
return this.metrics.filter(m => m.name === name)
}
return this.metrics
}
/**
* 获取平均时间
*/
getAverage(name) {
const metrics = this.getMetrics(name)
if (metrics.length === 0) return 0
const total = metrics.reduce((sum, m) => sum + m.duration, 0)
return total / metrics.length
}
/**
* 清空指标
*/
clear() {
this.metrics = []
}
}
/**
* 数据预加载管理器
*/
class PreloadManager {
constructor() {
this.preloadQueue = []
this.maxConcurrent = 3
this.running = 0
}
/**
* 添加预加载任务
*/
add(task, priority = 0) {
this.preloadQueue.push({ task, priority })
this.preloadQueue.sort((a, b) => b.priority - a.priority)
this.process()
}
/**
* 处理队列
*/
async process() {
while (this.running < this.maxConcurrent && this.preloadQueue.length > 0) {
const { task } = this.preloadQueue.shift()
this.running++
try {
await task()
} catch (e) {
console.error('预加载失败:', e)
} finally {
this.running--
this.process()
}
}
}
/**
* 清空队列
*/
clear() {
this.preloadQueue = []
}
}
// 创建全局实例
const cacheManager = new CacheManager()
const performanceMonitor = new PerformanceMonitor()
const preloadManager = new PreloadManager()
// 定期清理过期缓存
setInterval(() => {
cacheManager.cleanup()
}, 60 * 1000) // 每分钟清理一次
module.exports = {
debounce,
throttle,
CacheManager,
cacheManager,
LazyLoadManager,
PaginationManager,
PerformanceMonitor,
performanceMonitor,
PreloadManager,
preloadManager
}