缓存实现代码

/** 
 * 全能型获取图片缓存 (兼容单个链接与链接数组 + 秒开优化)
 */
export function getImageStorage(url) {
  return new Promise((resolve) => {
    // 1. 如果是数组,通过 map 循环调用自身,并用 Promise.all 等待所有结果
    if (Array.isArray(url)) {
      Promise.all(url.map(item => getImageStorage(item)))
        .then(results => resolve(results))
        .catch(() => resolve(url)); // 异常兜底,返回原数组
      return;
    }

    // 2. 单个链接处理逻辑
    if (!url) {
      resolve(''); 
      return;
    }
    
    // 智能处理 baseUrl 拼接(防止完整的 http/https 链接被重复拼接)
    // 注意:请确保你的工具文件里已经定义了 baseUrl,如果 url 已经是完整链接则不拼接
    const fullUrl = (url.startsWith('http://') || url.startsWith('https://')) 
      ? url 
      : (typeof baseUrl !== 'undefined' ? baseUrl + url : url);

    // 提取文件名作为缓存 key(兼容带参数的 OSS 链接)
    const pathWithoutQuery = fullUrl.split('?')[0];
    const fullFileName = pathWithoutQuery.substring(pathWithoutQuery.lastIndexOf('/') + 1);
    const fileNameWithoutExt = fullFileName.substring(0, fullFileName.lastIndexOf('.')) || fullFileName;
    
    const storageKey = "IMG_CACHE_" + fileNameWithoutExt; // 本地文件路径缓存 key
    const urlCacheKey = "URL_CACHE_" + fileNameWithoutExt; // 网络链接兜底缓存 key

    // --- 核心秒开逻辑:优先读取本地缓存的下载路径 ---
    const localUrl = uni.getStorageSync(storageKey);
    if (localUrl) {
      uni.setStorageSync(urlCacheKey, fullUrl); // 顺便更新一下网络链接缓存
      resolve(localUrl); 
      return;
    }

    // --- 核心秒开逻辑:如果没有本地文件,看看有没有缓存的网络链接 ---
    const cachedUrl = uni.getStorageSync(urlCacheKey);
    if (cachedUrl) {
      resolve(cachedUrl); // 立刻返回缓存的链接,让页面先渲染出来(实现秒开)
    }

    // 3. 执行下载和持久化缓存逻辑
    // #ifndef H5
    uni.downloadFile({
      url: fullUrl,
      success: (res) => {
        if (res.statusCode === 200) {
          const saveSuccess = (savedFilePath) => {
            uni.setStorageSync(storageKey, savedFilePath);
            uni.setStorageSync(urlCacheKey, fullUrl);
            resolve(savedFilePath);
          };
          const saveFail = () => resolve(fullUrl); // 失败兜底返回原链接

          // #ifndef MP-WEIXIN || MP-KUAISHOU
          uni.saveFile({ tempFilePath: res.tempFilePath, success: (r) => saveSuccess(r.savedFilePath), fail: saveFail });
          // #endif
          // #ifdef MP-WEIXIN
          wx.getFileSystemManager().saveFile({ tempFilePath: res.tempFilePath, success: (r) => saveSuccess(r.savedFilePath), fail: saveFail });
          // #endif
          // #ifdef MP-KUAISHOU
          ks.saveFile({ tempFilePath: res.tempFilePath, success: (r) => saveSuccess(r.savedFilePath), fail: saveFail });
          // #endif
        } else {
          resolve(fullUrl);
        }
      },
      fail: () => resolve(fullUrl),
    })
    // #endif

    // #ifdef H5
    // H5端 fetchBlobDataAsBase64 逻辑(需确保你文件里有这个辅助函数)
    fetchBlobDataAsBase64(fullUrl)
      .then(base64Data => {
        const [header, data] = base64Data.split(',');
        const mimeType = header.match(/:(.*?);/)[1];
        const base64 = `data:${mimeType};base64,${data}`;
        uni.setStorageSync(storageKey, base64);
        uni.setStorageSync(urlCacheKey, fullUrl);
        resolve(base64);
      })
      .catch(() => resolve(fullUrl))
    // #endif
  });
}

// H5端辅助函数
function fetchBlobDataAsBase64(blobUrl) {
  return new Promise((resolve, reject) => {
    fetch(blobUrl)
      .then(response => response.blob())
      .then(blob => {
        const reader = new FileReader();
        reader.onloadend = () => resolve(reader.result);
        reader.onerror = () => reject(new Error('无法读取文件'));
        reader.readAsDataURL(blob);
      })
      .catch(error => reject(error));
  });
}

使用方法

引入方法--import {getImageStorage} from '../../../util/chatImage.js',根据实际项目写入正确路劲。

在首次获取图片资源的时候调用方法,实现数据缓存this.rulesImageUrl = await getImageStorage(res.data.rulesImageUrl);

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐