HarmonyOS CacheUtil 进阶:缓存设计模式与典型应用场景

HarmonyOS CacheUtil 进阶:缓存设计模式与典型应用场景 文章目录背景一、CacheUtil 的应用层次二、模式一安全读取模式三、模式二惰性初始化Lazy Load四、模式三ClickUtil 防抖的依赖关系五、模式四防重复请求标记六、模式五退出登录时清理七、缓存 UI 展示八、CacheUtil 的局限性九、命名规范建议十、小结背景近期发现一款很有意思的HarmonyOS 三方库, 地址 pura/harmony-utils(V1.4.0) , 作者是桃花镇童长老, 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦案例demo导航展示↓↓↓↓↓↓接下来言归正传 ↓↓↓↓一、CacheUtil 的应用层次CacheUtil看起来只是一个简单的键值存储但在实际开发中可以承担多种角色工具基础设施作为其他工具类的底层存储如ClickUtil的防抖页面级缓存同一页面多次访问的数据缓存跨组件状态共享替代简单的全局变量防重复请求标记正在进行的网络请求防止重复发起效果演示二、模式一安全读取模式最常见的缓存读取方式应该配合has()判断// 不推荐直接 get可能返回 undefinedconsttokenCacheUtil.getstring(userToken);// 如果 token 为 undefined后续使用会报错// 推荐先 has 再 getif(CacheUtil.has(userToken)){consttokenCacheUtil.getstring(userToken);// 安全使用 token}else{// 处理不存在的情况}Demo 中也遵循了这个模式cacheGet(){if(this.cacheKeyInput.trim()){this.addLog(Cache,请输入 Key,warn);return;}consthasCacheUtil.has(this.cacheKeyInput.trim());if(!has){this.addLog(Cache,Key ${this.cacheKeyInput} 不存在,warn);return;}constvalCacheUtil.getstring|number|boolean(this.cacheKeyInput.trim());this.addLog(Cache,get(${this.cacheKeyInput}) ${val},success);}三、模式二惰性初始化Lazy Load适合计算代价较高的数据// 只计算一次后续直接从缓存读取functiongetExpensiveConfig():Config{constCACHE_KEYapp_config;if(!CacheUtil.has(CACHE_KEY)){constconfigcomputeExpensiveConfig();// 耗时计算CacheUtil.putConfig(CACHE_KEY,config);}returnCacheUtil.getConfig(CACHE_KEY);}四、模式三ClickUtil 防抖的依赖关系ClickUtil的防抖实现完全依赖CacheUtil这是工具类协作的典型示例// ClickUtil 内部的防抖实现staticdebounce(func:()void,wait:number1000,clickId:stringClickUtil.defaultId){// 1. 从 CacheUtil 读取上一次的 timeoutIDletcacheIDCacheUtil.getnumber(ClickUtil_debounce_timeoutID_${clickId});// 2. 如果存在清除上一次的定时器if(cacheID!undefinedcacheID!null){clearTimeout(cacheID);}// 3. 设置新的定时器lettimeoutIDsetTimeout((){typeoffuncfunctionfunc();clearTimeout(timeoutID);},wait);// 4. 将新的 timeoutID 存入 CacheUtilCacheUtil.putnumber(ClickUtil_debounce_timeoutID_${clickId},timeoutID);}CacheUtil在这里充当了跨调用的状态存储每次调用debounce都是独立的函数调用但通过CacheUtil可以访问上一次调用存储的状态。五、模式四防重复请求标记constLOADING_KEYisUserInfoLoading;asyncfunctionloadUserInfo(){// 防止重复请求if(CacheUtil.has(LOADING_KEY)CacheUtil.getboolean(LOADING_KEY)){return;}CacheUtil.putboolean(LOADING_KEY,true);try{constuserawaitfetchUserInfo();CacheUtil.putUserInfo(userInfo,user);}finally{CacheUtil.remove(LOADING_KEY);// 无论成功失败都要清除标记}}六、模式五退出登录时清理用户退出登录时需要清理所有与用户相关的缓存functiononLogout(){// 方式一逐个删除已知的 keyCacheUtil.remove(userToken);CacheUtil.remove(userInfo);CacheUtil.remove(userPermissions);// 方式二一键清空全部适合缓存全为用户数据的场景CacheUtil.clear();// 方式三只清除业务缓存保留工具缓存// 这时需要约定好 key 的命名规范}在 Demo 中点击清空全部缓存按钮就演示了clear()的效果cacheClearAll(){CacheUtil.clear();this.addLog(Cache,clear() 所有缓存已清空,success);this.refreshCacheList();}七、缓存 UI 展示Demo 中展示了如何实时展示缓存内容// 缓存列表展示Column(){Text(缓存内容).fontSize(13).fontColor(#666).fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:8})if(this.cacheEntries.length0){Text(暂无缓存数据).fontSize(12).fontColor(#CCC).width(100%).textAlign(TextAlign.Center).padding({top:16,bottom:16})}else{ForEach(this.cacheEntries,(e:CacheEntry){Row(){Text(e.key).fontSize(12).fontColor(#D63384).fontFamily(monospace).layoutWeight(0.8).maxLines(1)Text(:${e.value}).fontSize(12).fontColor(#555).layoutWeight(1.2).maxLines(1)Text(e.type).fontSize(10).fontColor(#888)}.width(100%).padding({top:6,bottom:6})},(e:CacheEntry)e.key)}}八、CacheUtil 的局限性特性CacheUtil替代方案持久化❌ 重启丢失PreferencesUtil用户首选项加密存储❌ 明文AssetUtil关键资产容量限制受内存限制数据库或文件类型安全弱需手动 as使用 TypeScript 接口跨进程共享❌共享偏好设置九、命名规范建议使用CacheUtil时key 命名建议遵循以下规范避免冲突// 使用模块前缀user_token// 用户模块config_theme// 配置模块click_debounce_xxx// ClickUtil 内部用已有命名规范// 避免过于简单的 keytoken// 容易与其他地方冲突data// 完全不知道存的是什么十、小结CacheUtil虽然只有 6 个方法但通过不同的使用模式可以解决安全读取has()get()组合惰性初始化避免重复计算工具协作为ClickUtil等提供状态存储防重复操作标记进行中的异步操作批量清理登出时clear()一键清空理解CacheUtil的设计也有助于理解整个 HoUtils 工具集内部的依赖关系。