5.2 本地存储方案


文档摘要

5.2 本地存储方案 本节导读:store 解决"活着的时候共享",存储解决"重启之后还在"。本节讲 uni 存储的同步异步两套 API 与各端容量约束,对照 H5 端 indexedDB 与 App 端 SQLite 的分工,最后给出商城的三层存储封装——读这一节前先记住一个数字:小程序端单键与总量都有上限,存储不是数据库。 两套 API 与一个使用公约 uni.setStorage 家族分异步(setStorage 加 success 回调或 promise)与同步(setStorageSync)两套。选择标准不是"哪个高级":同步版在启动恢复、轻量配置读取这类短平快场景最省心;异步版用于稍大数据或启动路径上不该阻塞的操作。

5.2 本地存储方案

本节导读:store 解决"活着的时候共享",存储解决"重启之后还在"。本节讲 uni 存储的同步异步两套 API 与各端容量约束,对照 H5 端 indexedDB 与 App 端 SQLite 的分工,最后给出商城的三层存储封装——读这一节前先记住一个数字:小程序端单键与总量都有上限,存储不是数据库。

两套 API 与一个使用公约

uni.setStorage 家族分异步(setStorage 加 success 回调或 promise)与同步(setStorageSync)两套。选择标准不是"哪个高级":同步版在启动恢复、轻量配置读取这类短平快场景最省心;异步版用于稍大数据或启动路径上不该阻塞的操作。真正的公约只有一条——启动路径上的存储读取总量要克制,同步读十几个键的开销在小程序冷启动指标里能被量出来,商城把启动必需的读取收敛到三个键以内,其余懒加载。基本用法与易错点一并给出:

// 写:异步版,失败要接住(容量超限在这里暴露) uni.setStorage({ key: 'recent-search', data: ['连衣裙', '运动鞋', '蓝牙耳机'], fail(err) { console.warn('存储写入失败,可能超限:', err); } }); // 读:同步版,取不到返回空串而非 null——判空要用假值判断 const hist = uni.getStorageSync('recent-search'); if (!hist || !hist.length) { console.log('还没有搜索历史'); } // 删与清 uni.removeStorageSync('recent-search'); // uni.clearStorageSync(); // 清全部,慎用:会把 token 一起清掉

getStorageSync 取不到返回空字符串而不是 null,是新手高发的判断错误;clearStorageSync 一键清场连登录态一起带走,调用前先想清楚范围。容量方面,小程序端单键上限一兆、总量上限十兆;H5 端落在浏览器存储上,配额随浏览器不同;App 端最宽裕,但清数据、卸载都会清库。

各端的进阶选项:indexedDB 与 SQLite

存储家族满足不了"本地大量结构化数据"时,各端各有进阶选项,分工按端划清。H5 端的 indexedDB:浏览器原生的键值数据库,容量以兆上百计,适合离线商品缓存、草稿箱这类大数据量;小程序端没有它,别在公共代码里直接引用。App 端的 SQLite:plus 运行时提供真正的关系型本地库,适合报表离线包、采集类应用的大批量记录;操作走 plus 的 API 或封装库,写法与 Web 完全不同,务必圈进条件编译。各端通用的折中是"数据切片加索引键":把大列表按页拆成多个存储键,另存一个索引键记录分页信息——它跑在 uni 存储上,三端行为一致,代价是自己维护分片逻辑。商城的选择务实:聊天会话草稿这类小数据走 uni 存储,离线商品包只在 App 端用 SQLite 实现,H5 端降级为"网络可用时拉取"。

三层封装:键名、类型与降级各归一层

散落的 setStorageSync 调用是存储事故的主要来源(键名写错、类型漂移、超限无人知)。商城的封装分三层,每层只管一件事:

// utils/storage.js —— 三层存储封装 const PREFIX = 'shop_'; // 第一层:键名空间,防撞名 const KEYS = { TOKEN: 'token', SEARCH_HISTORY: 'search-history', CART: 'cart-items' }; function realKey(key) { return PREFIX + key; } // 第二层:类型与判空收口 export function getJSON(key, fallback = null) { try { const raw = uni.getStorageSync(realKey(key)); return raw ? JSON.parse(raw) : fallback; } catch (e) { return fallback; // 坏数据按缺失处理,不让启动崩 } } export function setJSON(key, val) { try { uni.setStorageSync(realKey(key), JSON.stringify(val)); return true; } catch (e) { // 第三层:超限降级——历史上删最旧的一半 if (key === KEYS.SEARCH_HISTORY) { uni.removeStorageSync(realKey(key)); return false; } console.warn('存储写入失败:', key, e); return false; } } export function removeKey(key) { uni.removeStorageSync(realKey(key)); }

三层各自的收益:键名空间让多工程共存与排查时按键名一眼定位归属;类型收口让"存进去是对象、取出来变字符串"这类事故在封装层绝迹;降级策略集中在一处,容量问题不再以"用户手机上莫名报错"的形态爆发。敏感数据(token)的加分项是在 App 端用 plus 的偏好加密存储,条件编译圈定,H5 端至少加一层可逆混淆并接受"本地存储天然可读"的现实,别把敏感度超出存储能力的数据放进来。

存储联调的三个自检问题

联调期遇到存储类问题,按三个自检问题走。第一问,键名空间对吗:用封装层的真实键名(带前缀)直接查一遍原始存储,排除前缀拼错与大小写差异。第二问,写入时机对吗:异步写入失败或页面卸载早于写入完成,都会造成"明明调了 set 却读不到",把关键写入改成同步或补 fail 回调即可定位。第三问,端别对吗:模拟器与真机的存储不互通,清缓存行为也不同,别在模拟器验证完就断定真机同样成立。三个问题过完仍未解决,把读写时序打上日志,问题通常自己浮出来。

本节要点回顾

  • 同步版适合启动期轻量读取,异步版配 fail 回调接容量错误;启动期读取收敛到三个键内;
  • getStorageSync 取不到返回空串,判空用假值判断;clear 会连登录态一起清;
  • 小程序端单键一兆、总量十兆,存储不是数据库,大数据按端走 indexedDB 或 SQLite;
  • 三层封装各管一件事:键名空间、类型判空、超限降级,事故率由此收敛;
  • 敏感数据按端选择加密通道,并清醒认识本地存储的可读本质。

持久层就位,下一节向上回到网络:请求封装、拦截器与错误归一的管道设计。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U