资讯专栏INFORMATION COLUMN

如何构建通用存储中间层

hersion / 1982人阅读

摘要:并且数据同步后默认会保存下来,这样下次再请求时存储层中就有数据了。以下参数会传到中这么一来,存储层就和接口层对接起来了。五支持永久保存在某些场景下,可能不方便写过期时间,这时默认可以传递,标记该数据永不过期。

零、问题的由来

开门见山地说,这篇文章【又】是一篇安利软文~,安利的对象就是 tua-storage。

顾名思义,这就是一款存储数据的工具。

</>复制代码

  1. 用 tua-storage 好处大大的有么?

那必须滴~,下面开始我的表演~

多端统一 api

支持数据同步

数据过期逻辑

自动清理过期数据

支持永久保存

支持批量操作

一、多端统一 api

日常开发中,在不同的平台下由于有不同的存储层接口,所以往往导致相同逻辑的同一份代码要写几份儿。

例如,小程序中保存数据要使用【异步】的 wx.setStoragewx.getStorage 或对应的同步方法;

而在 web 端使用 localStorage 的话,则是【同步】的 setItemgetItem 等方法;

在 React-Native 的场景下,使用的又是 AsyncStorage 中【异步】的 setItemgetItem...

1.1.异步方法

然而,经过 tua-storage 的二次封装,以上两个方法统一变成了:

save: 异步保存

load: 异步读取

此外还有一些其他方法:

clear: 异步清除(删除多个)

remove: 异步删除(删除单个)

getInfo: 异步获取信息(如 keys

详情参阅这里的文档

1.2.同步方法

在某些场景下正好需要调用同步方法的话,咋办咧?

与 Node.js 的 api 风格差不多,在上述异步方法后面加上 Sync 就是对应的同步方法:

saveSync

loadSync

clearSync

removeSync

getInfoSync

那么在 AsyncStorage 的场景下,压根就没有同步方法时调用以上方法会怎么样呢?

嗯,你猜得没错,会直接报错...

1.3.区分场景

</>复制代码

  1. 如何区分不同的场景呢?

在初始化的时候传递 storageEngine 即可:

</>复制代码

  1. import TuaStorage from "tua-storage"
  2. const tuaStorage = new TuaStorage({
  3. // 小程序
  4. storageEngine: wx,
  5. // web
  6. storageEngine: localStorage,
  7. // React-Native
  8. storageEngine: AsyncStorage,
  9. // Node.js
  10. storageEngine: {},
  11. })

</>复制代码

  1. 注意:传递的是【对象】,而非字符串!
二、支持数据同步

对于一个二次封装多端存储层的库来说,保证多端 api 的统一仅仅是常规操作而已。

tua-storage 的另一大亮点就是数据同步功能。

想想平时我们是怎么使用存储层的

读取一个数据

正好存储层里有这个数据

返回数据(皆大欢喜,happy ending~)

假如存储层里没这个数据

手动调用各种方法去同步这个数据

手动存到存储层中,以便下次读取

</>复制代码

  1. 各位有没有看出其中麻烦的地方在哪儿?

    数据同步部分的复杂度全留给了业务侧。

让我们回归这件事的【初心】:我仅仅需要获取这个数据!我不管它是来自存储层、来自接口数据、还是来自其他什么地方...

2.1.数据同步函数

因此 tua-storage 在读取数据时很贴心地提供了一个 syncFn 参数,作为数据同步的函数,当请求的数据不存在或已过期时自动调用该函数。并且数据同步后默认会保存下来,这样下次再请求时存储层中就有数据了。

syncParams 的使用场景是接口需要传参时,这些参数会传给 syncFn

</>复制代码

  1. tuaStorage.load({
  2. key: "some data",
  3. syncFn: ({ a }) => axios("some api url" + a),
  4. // 以下参数会传到 syncFn 中
  5. syncParams: { a: "a" },
  6. })

这么一来,存储层就和接口层对接起来了。业务侧再也不用手动调用 api 获取数据。

2.2.合并分散配置

每次读取数据时如果都要手动传同步函数,实际编码时还是很麻烦...

</>复制代码

  1. 不急,吃口药~

tua-storage 在初始化时能够传递一个叫做 syncFnMap 参数。顾名思义,这是一个将 keysyncFn 映射起来的对象。

</>复制代码

  1. const tuaStorage = new TuaStorage({
  2. // ...
  3. syncFnMap: {
  4. "data one": () => axios("data one api"),
  5. "data two": () => axios("data two api"),
  6. // ...
  7. },
  8. })
  9. // 不用手动传 syncFn,默认匹配 syncFnMap 中的对应函数
  10. tuaStorage.load({ key: "data one" })
2.3.自动生成配置

其实手动编写每个 api 请求函数也是很繁琐的,要是有个根据配置自动生成请求函数的库就好了~

诶~,巧了么不是~。各位开发者老爷们了解一下同样跨平台的 tua-api ~?

tua-storage 搭配 tua-api 之后会变成这样

</>复制代码

  1. import TuaStorage from "tua-storage"
  2. import { getSyncFnMapByApis } from "tua-api"
  3. // 本地写好的各种接口配置
  4. import * as apis from "@/apis"
  5. const tuaStorage = new TuaStorage({
  6. syncFnMap: getSyncFnMapByApis(apis),
  7. })
三、数据过期逻辑

一般各个平台的存储层都没有数据过期这一逻辑。但在使用 tua-storage 时默认每个数据都有过期时间这一属性。

3.1.默认过期时间

默认为 30 秒,可以在初始化时配置默认超时时间。

</>复制代码

  1. import TuaStorage from "tua-storage"
  2. const tuaStorage = new TuaStorage({
  3. // 改为 60 秒
  4. defaultExpires: 60,
  5. })
  6. // 返回一个 Promise
  7. tuaStorage
  8. .save({
  9. key: "data key",
  10. data: { foo: "bar" },
  11. // 这里传递的过期时间优先级更高
  12. expires: 90,
  13. })
  14. .then(console.log)
  15. .catch(console.error)
  16. // 保存到 storage 中的数据大概长这样
  17. // key 之前会加上初始化传入的默认前缀
  18. {
  19. "TUA_STORAGE_PREFIX: data key": {
  20. expires: 90,
  21. rawData: { foo: "bar" },
  22. },
  23. }
3.2.数据保存前缀

为了保证存在 storage 中的数据名称不冲突,以及实现版本控制,tua-storage 默认有一个存储前缀:storageKeyPrefix

默认值为 TUA_STORAGE_PREFIX: ,所以在上一小节中保存的数据会有一个奇怪的前缀。

</>复制代码

  1. 保证名称不冲突很好理解,如何实现版本控制呢?
3.3.白名单机制

clear 函数能够接受一个白名单数组(因为内部是通过 indexOf 来判断的,所以不必填写完整的 key 值)。

</>复制代码

  1. import TuaStorage from "tua-storage"
  2. const tuaStorage = new TuaStorage({ ... })
  3. tuaStorage.clear(["key"])
  4. .then(console.log)
  5. .catch(console.error)
  6. // 假设现在 storage 中有以下数据
  7. {
  8. "foo": {},
  9. "bar": {},
  10. "foo-key": {},
  11. "bar-key": {},
  12. }
  13. // 清除后剩下的数据是
  14. {
  15. "foo-key": {},
  16. "bar-key": {},
  17. }

所以在调用 clear 时,在白名单中传入新的存储前缀,即可实现删除上一版本数据的功能。

</>复制代码

  1. import TuaStorage from "tua-storage"
  2. // 上一版本的前缀
  3. const prefix1 = "STORAGE_PREFIX_V1.0: "
  4. // 这一版本的前缀
  5. const prefix2 = "STORAGE_PREFIX_V1.1: "
  6. const tuaStorage = new TuaStorage({
  7. // 将默认前缀切换成新版本的
  8. storageKeyPrefix: prefix2,
  9. })
  10. // 开始清除上个版本的数据
  11. tuaStorage.clear([ prefix2 ])
  12. .then(console.log)
  13. .catch(console.error)

更多默认配置参阅这里的文档

四、自动清理过期数据

默认在启动时会进行一次过期数据清理(可以关闭),之后每过一段时间会再次清理。

</>复制代码

  1. 什么样的数据会被清理呢?
4.1.清理逻辑

首先当然是清理已到过期时间的数据,即有一个属性为 expires 的数据,且当前时间已超过了该时间。

一旦遇到不满足格式的数据(非对象、没有 expires 属性)则跳过,这样就不会误清除其他程序保存的数据。

4.2.清理时间间隔

在初始化时可传入 autoClearTime 修改默认自动清理时间间隔。

默认为一分钟,注意是以秒为单位。

五、支持永久保存

在某些场景下,可能不方便写过期时间,这时默认可以传递 expires: null,标记该数据永不过期。

</>复制代码

  1. 不喜欢用 null 标记?

大丈夫~,初始化时传递 neverExpireMark 即可修改为你喜欢的别的标记。

</>复制代码

  1. import TuaStorage from "tua-storage"
  2. const tuaStorage = new TuaStorage({
  3. neverExpireMark: "never",
  4. })
  5. // 永不过期
  6. tuaStorage.save({
  7. key: "some key",
  8. data: "some data",
  9. expires: "never",
  10. })
六、支持批量操作

假设现在有一组数据需要保存或读取,常规操作就是使用 Promise.all 发起多个操作。

</>复制代码

  1. import TuaStorage from "tua-storage"
  2. const tuaStorage = new TuaStorage({ ... })
  3. const dataToBeSaved = [
  4. { key: "key one", data: "some data" },
  5. { key: "key two", data: "some data" },
  6. ]
  7. // 异步
  8. const result = dataToBeSaved
  9. .map(tuaStorage.save.bind(tuaStorage))
  10. .then(Promise.all.bind(Promise))
  11. // 同步
  12. const result = dataToBeSaved
  13. .map(tuaStorage.saveSync.bind(tuaStorage))

讲道理这样写还是挺烦的...所以 tua-storage 的各个 api 还支持直接传入数组:

</>复制代码

  1. // 异步
  2. tuaStorage.save(dataToBeSaved)
  3. .then(console.log)
  4. .catch(console.log)
  5. // 同步
  6. tuaStorage.saveSync(dataToBeSaved)
七、小结

还在为 web 端、小程序端、React-Native 端、node 端业务侧代码使用不一样的方式调用存储层烦恼么?还在为手动数据同步,保存数据,处理过期逻辑而烦躁么?各位开发者老爷们不妨试一试 tua-storage,(挤需体验三番钟,里造会干我一样,爱象介款工具)。

灵感来源

inspired by react-native-storage

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108770.html

相关文章

  • 将军令:数据安全平台建设实践

    摘要:解决方案如图所示,将军令分块,数据内容权限平台审批流平台审计日志平台提供各种灵活可插拔的服务,支持在通用服务的基础基础上进行定制开发。 背景 在大数据时代,数据已经成为公司的核心竞争力。此前,我们介绍了美团酒旅起源数据治理平台的建设与实践,主要是通过各种数据分析挖掘手段,为公司发展决策和业务开展提供数据支持。 近期,业内数据安全事件频发,给相关企业造成了无可挽回的损失,更为数据安全防护...

    vpants 评论0 收藏0
  • 将军令:数据安全平台建设实践

    摘要:解决方案如图所示,将军令分块,数据内容权限平台审批流平台审计日志平台提供各种灵活可插拔的服务,支持在通用服务的基础基础上进行定制开发。 背景 在大数据时代,数据已经成为公司的核心竞争力。此前,我们介绍了美团酒旅起源数据治理平台的建设与实践,主要是通过各种数据分析挖掘手段,为公司发展决策和业务开展提供数据支持。 近期,业内数据安全事件频发,给相关企业造成了无可挽回的损失,更为数据安全防护...

    Binguner 评论0 收藏0
  • 如何构建通用 api 间层

    摘要:是在收到响应后执行的函数,可以不用返回。一步步介绍了如何构建以及使用中间层,来统一管理接口地址,最后还介绍了下中间件等高级功能。 零、问题的由来 开门见山地说,这篇文章是一篇安利软文~,安利的对象就是最近搞的 tua-api。 顾名思义,这就是一款辅助获取接口数据的工具。 发请求相关的工具辣么多,那我为啥要用你呢? 理想状态下,项目中应该有一个 api 中间层。各种接口在这里定义,业务...

    BingqiChen 评论0 收藏0
  • 进阶Java架构师必看的15本书

    摘要:阿里巴巴的共享服务理念以及企业级互联网架构建设的思路,给这些企业带来了不少新的思路,这也是我最终决定写这本书的最主要原因。尽在双阿里巴巴技术演进与超越是迄今唯一由阿里巴巴集团官方出品全面阐述双八年以来在技术和商业上演进和创新历程的书籍。 showImg(https://segmentfault.com/img/remote/1460000015386860); 1、大型网站技术架构:核...

    Julylovin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<