feat(图片缓存文件): 优化执行逻辑

This commit is contained in:
hzj 2026-03-06 19:09:52 +08:00
parent f3521f5917
commit 1cc0469872

View File

@ -11,14 +11,14 @@ class ImageCacheManager {
this.imageCacheName = `likei-images-v${this.currentImageVersion}` // OSS图片 this.imageCacheName = `likei-images-v${this.currentImageVersion}` // OSS图片
this.assetCacheName = `likei-assets-v${this.currentImageVersion}` // 本地assets this.assetCacheName = `likei-assets-v${this.currentImageVersion}` // 本地assets
this.maxCacheItems = 200 // 最大缓存数量(100张 this.maxCacheItems = 200 // 最大缓存数量(200张
this.maxCacheSize = 200 * 1024 * 1024 // 最大缓存大小(100MB this.maxCacheSize = 200 * 1024 * 1024 // 最大缓存大小(200MB
this.currentImageCacheSize = 0 // 当前image缓存大小字节 this.currentImageCacheSize = 0 // 当前image缓存大小字节
this.currentAssetCacheSize = 0 // 当前asset缓存大小字节 this.currentAssetCacheSize = 0 // 当前asset缓存大小字节
this.pendingRequests = new Map() // { url: { promise, retries } } this.requestScheduler = new Map() // 上层请求调度器: CORS 降级处理 Promise 或 error
this.pendingRequests = new Map() // 底层请求管理:包含重试次数 { url: { promise, retries } }
this.maxRetries = 3 // 最大重试次数 this.maxRetries = 3 // 最大重试次数
this.requestScheduler = new Map() // 请求调度器
this.init() this.init()
} }
@ -319,6 +319,7 @@ class ImageCacheManager {
const { cache, cacheName } = await this.getCacheForUrl(normalizedUrl) // 选中对应缓存 const { cache, cacheName } = await this.getCacheForUrl(normalizedUrl) // 选中对应缓存
// 尝试多种匹配方式 // 尝试多种匹配方式
// 带配置的 Request 对象匹配:严格匹配具有特定 CORS 配置和凭证策略的缓存响应,确保请求模式一致
let cachedResponse = await cache.match( let cachedResponse = await cache.match(
new Request(normalizedUrl, { new Request(normalizedUrl, {
mode: 'cors', mode: 'cors',
@ -326,10 +327,13 @@ class ImageCacheManager {
}), }),
) )
// URL 字符串精确匹配:最基础的匹配方式,查找缓存中 URL 完全一致的请求记录
if (!cachedResponse) { if (!cachedResponse) {
cachedResponse = await cache.match(normalizedUrl) cachedResponse = await cache.match(normalizedUrl)
} }
// 忽略查询参数的 URL 匹配
// 通过 urlObj.origin 和 urlObj.pathname 拼接生成 urlWithoutQuery去除查询参数如时间戳、token 等)后进行匹配。用于兼容同一资源因携带不同查询参数而导致 URL 不同,但实际资源内容相同的场景。
if (!cachedResponse) { if (!cachedResponse) {
const urlObj = new URL(normalizedUrl) const urlObj = new URL(normalizedUrl)
const urlWithoutQuery = `${urlObj.origin}${urlObj.pathname}` const urlWithoutQuery = `${urlObj.origin}${urlObj.pathname}`
@ -361,13 +365,14 @@ class ImageCacheManager {
return URL.createObjectURL(blob) return URL.createObjectURL(blob)
} }
// 3. 创建新的请求并记录到 pendingRequests // 3. 请求和缓存都没有
// 1创建新的请求并记录到 pendingRequests
const loadPromise = this.createLoadPromise(normalizedSrc) const loadPromise = this.createLoadPromise(normalizedSrc)
this.pendingRequests.set(normalizedSrc, { this.pendingRequests.set(normalizedSrc, {
promise: loadPromise, promise: loadPromise,
retries: this.maxRetries, retries: this.maxRetries, // 记录重试次数
}) })
// 2执行请求
try { try {
const result = await loadPromise const result = await loadPromise
return result return result
@ -377,7 +382,7 @@ class ImageCacheManager {
} }
} }
// 请求调度器:确保所有请求统一管理 // 上层请求调度器:确保所有请求统一管理
async scheduleRequest(src) { async scheduleRequest(src) {
const normalizedSrc = this.normalizeUrl(src) const normalizedSrc = this.normalizeUrl(src)
@ -400,32 +405,26 @@ class ImageCacheManager {
} }
// 否则创建新请求并加入调度器 // 否则创建新请求并加入调度器
const requestPromise = this.loadImage(src).catch((error) => { const requestPromise = this.loadImage(src)
// 标记失败请求 this.requestScheduler.set(normalizedSrc, requestPromise) // 不记录重试次数,只存 Promise
this.requestScheduler.set(normalizedSrc, error)
throw error
})
this.requestScheduler.set(normalizedSrc, requestPromise)
try { try {
const result = await requestPromise return await requestPromise
return result
} finally { } finally {
// 清理调度器中的记录 this.requestScheduler.delete(normalizedSrc) // 清理调度器中的记录
this.requestScheduler.delete(normalizedSrc)
} }
} }
// 创建加载 Promise含重试逻辑 // 创建加载 Promise含重试逻辑
async createLoadPromise(src) { async createLoadPromise(src) {
const normalizedSrc = this.normalizeUrl(src) // 冗余步骤(作为防御性编程)
// const normalizedSrc = this.normalizeUrl(src)
// 新增:检查是否已有相同请求正在进行 // // 新增:检查是否已有相同请求正在进行
if (this.pendingRequests.has(normalizedSrc)) { // if (this.pendingRequests.has(normalizedSrc)) {
console.warn(`请求已存在,跳过重复加载: ${src}`) // console.warn(`请求已存在,跳过重复加载: ${src}`)
return this.pendingRequests.get(normalizedSrc).promise // return this.pendingRequests.get(normalizedSrc).promise
} // }
const attemptLoad = async (retriesLeft) => { const attemptLoad = async (retriesLeft) => {
try { try {