地址路径修改
This commit is contained in:
209
miniprogram/utils/avatarCache.ts
Normal file
209
miniprogram/utils/avatarCache.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 头像缓存管理工具类
|
||||
* 实现头像图片的KV存储和缓存机制,避免重复下载相同图片
|
||||
*/
|
||||
|
||||
class AvatarCache {
|
||||
private static instance: AvatarCache;
|
||||
private cache: Map<string, string> = new Map(); // KV存储:avatarUrl -> 本地图片路径
|
||||
private downloadingUrls: Set<string> = new Set(); // 正在下载的URL集合
|
||||
|
||||
private constructor() {}
|
||||
|
||||
public static getInstance(): AvatarCache {
|
||||
if (!AvatarCache.instance) {
|
||||
AvatarCache.instance = new AvatarCache();
|
||||
}
|
||||
return AvatarCache.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像图片路径
|
||||
* @param avatarUrl 头像URL
|
||||
* @returns 本地图片路径或Promise<string>
|
||||
*/
|
||||
public async getAvatarPath(avatarUrl: string): Promise<string> {
|
||||
if (!avatarUrl) {
|
||||
return this.getDefaultAvatarPath();
|
||||
}
|
||||
|
||||
// 如果缓存中已存在,直接返回
|
||||
if (this.cache.has(avatarUrl)) {
|
||||
return this.cache.get(avatarUrl)!;
|
||||
}
|
||||
|
||||
// 如果正在下载中,等待下载完成
|
||||
if (this.downloadingUrls.has(avatarUrl)) {
|
||||
return await this.waitForDownload(avatarUrl);
|
||||
}
|
||||
|
||||
// 开始下载图片
|
||||
return await this.downloadAndCacheAvatar(avatarUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像URL(用于存储和传递,不下载图片)
|
||||
* @param userId 用户ID
|
||||
* @param avatarUrl 头像URL
|
||||
* @returns 头像URL
|
||||
*/
|
||||
public getAvatarUrl(avatarUrl: string): string {
|
||||
if (!avatarUrl) {
|
||||
return '/images/user-avatar.png';
|
||||
}
|
||||
|
||||
// 如果缓存中已存在,直接返回URL(不下载)
|
||||
if (this.cache.has(avatarUrl)) {
|
||||
return avatarUrl;
|
||||
}
|
||||
|
||||
// 如果不在缓存中,异步下载但不等待结果
|
||||
if (!this.downloadingUrls.has(avatarUrl)) {
|
||||
this.downloadAndCacheAvatar(avatarUrl).catch(() => {
|
||||
// 下载失败不影响主流程
|
||||
});
|
||||
}
|
||||
|
||||
return avatarUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载并缓存头像图片
|
||||
* @param avatarUrl 头像URL
|
||||
* @returns 本地图片路径
|
||||
*/
|
||||
private async downloadAndCacheAvatar(avatarUrl: string): Promise<string> {
|
||||
this.downloadingUrls.add(avatarUrl);
|
||||
|
||||
try {
|
||||
// 下载图片到临时文件
|
||||
const tempFilePath = await this.downloadImage(avatarUrl);
|
||||
|
||||
// 缓存到KV存储
|
||||
this.cache.set(avatarUrl, tempFilePath);
|
||||
|
||||
return tempFilePath;
|
||||
} catch (error) {
|
||||
console.error(`下载头像失败: ${avatarUrl}`, error);
|
||||
return this.getDefaultAvatarPath();
|
||||
} finally {
|
||||
this.downloadingUrls.delete(avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载图片到本地临时文件
|
||||
* @param avatarUrl 头像URL
|
||||
* @returns 本地临时文件路径
|
||||
*/
|
||||
private async downloadImage(avatarUrl: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.downloadFile({
|
||||
url: avatarUrl,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
resolve(res.tempFilePath);
|
||||
} else {
|
||||
reject(new Error(`下载失败,状态码: ${res.statusCode}`));
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待下载完成
|
||||
* @param avatarUrl 头像URL
|
||||
* @returns 本地图片路径
|
||||
*/
|
||||
private async waitForDownload(avatarUrl: string): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
const checkInterval = setInterval(() => {
|
||||
if (!this.downloadingUrls.has(avatarUrl) && this.cache.has(avatarUrl)) {
|
||||
clearInterval(checkInterval);
|
||||
resolve(this.cache.get(avatarUrl)!);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// 设置超时时间
|
||||
setTimeout(() => {
|
||||
clearInterval(checkInterval);
|
||||
resolve(this.getDefaultAvatarPath());
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认头像路径
|
||||
* @returns 默认头像路径
|
||||
*/
|
||||
private getDefaultAvatarPath(): string {
|
||||
return '/images/user-avatar.png';
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载多个头像
|
||||
* @param avatarUrls 头像URL数组
|
||||
*/
|
||||
public async preloadAvatars(avatarUrls: string[]): Promise<void> {
|
||||
const uniqueUrls = [...new Set(avatarUrls)];
|
||||
|
||||
for (const url of uniqueUrls) {
|
||||
if (url && !this.cache.has(url) && !this.downloadingUrls.has(url)) {
|
||||
// 异步预加载,不等待结果
|
||||
this.downloadAndCacheAvatar(url).catch(() => {
|
||||
// 预加载失败不影响主流程
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载多个头像并等待所有加载完成
|
||||
* @param avatarUrls 头像URL数组
|
||||
*/
|
||||
public async preloadAvatarsAndWait(avatarUrls: string[]): Promise<void> {
|
||||
const uniqueUrls = [...new Set(avatarUrls)];
|
||||
const downloadPromises: Promise<string>[] = [];
|
||||
|
||||
for (const url of uniqueUrls) {
|
||||
if (url && !this.cache.has(url) && !this.downloadingUrls.has(url)) {
|
||||
// 同步预加载,等待结果
|
||||
downloadPromises.push(this.downloadAndCacheAvatar(url));
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadPromises.length > 0) {
|
||||
console.log(`🔄 [AvatarCache] 开始预加载 ${downloadPromises.length} 个头像`);
|
||||
await Promise.allSettled(downloadPromises);
|
||||
console.log(`✅ [AvatarCache] 头像预加载完成,缓存大小: ${this.cache.size}`);
|
||||
} else {
|
||||
console.log('ℹ️ [AvatarCache] 没有需要预加载的头像');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
public clearCache(): void {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存统计信息
|
||||
*/
|
||||
public getCacheStats(): { size: number; downloading: number } {
|
||||
return {
|
||||
size: this.cache.size,
|
||||
downloading: this.downloadingUrls.size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例实例
|
||||
export const avatarCache = AvatarCache.getInstance();
|
||||
|
||||
export default AvatarCache;
|
||||
Reference in New Issue
Block a user