这篇笔记是转载的我们组长写的前端数据层技术选型思考、仅用于个人学习。
# 开篇
这里提及的数据层是指业务数据层,类似于后台数据库在前端的一个映射。
数据层是一个应用的核心,相对于视图层来说,数据层不会涉及到 DOM 节点,只是逻辑代码和数据的组合,所以数据层更加容易抽象,也会更加通用,只要是 Js 环境都能运行,做单元测试也会更加容易。尤其是像日事清这种大型单页应用的数据层,非常庞大,非常复杂,只有在数据这一层打好基础,我们才能更加轻松自如的应对各种复杂的业务场景。V8 重构,数据层的设计是最耗时的,也是我思考最多的地方。
新的设计,新的思考,通常都意味着新技术的引入,相信大家也早就做好了心理准备
# 我的思考
在做 V8 数据层的设计之前,我就定了一个方向:「面向未来 3 年做设计」。V8 数据层,至少能满足未来 3 年的业务需求。
然后我就开始思考,未来三年,我们做的哪些业务场景可能会对数据层有非常高的要求,想到了 3 个场景:
- 数据实时同步(teambition 基于 websocket 已经实现)
- 前端强缓存(indexedDB)
- 离线使用(service worker)
然后又思考,基于我自己目前对数据层的认知,我觉得一个好的数据层应该有如下特点:
- 尽量通用,和 vue/react 等视图框架无关,方便移植
- 足够智能,基于数据流的模式, rxjs,方便从各种地方流入数据,比如 ajax,websocket,用户操作,pull/push
- 独立维护, npm 包,所有协作系统的前端产品,都可以基于这个数据层进行开发
- 具备 ORM 能力, backbone-relational,方便我们处理各种数据之间的关系
- 具备数据库的基本能力,比如表,索引, 排序,limit ,skip
- 类型系统,方便开发者调用, typescript
然后又思考,基于我们定的微前端的架构,我们的数据层应该是什么样子的:
- 数据共享,前端统一维护一个数据层,所有子应用都基于这个数据层进行开发,方便业务数据共享
- 接口统一,减少迁移和学习成本
然后又思考,基于我们旧版的数据层设计,我们的数据层应该是什么样子的:
- 每个模块的数据需要独立 vuex namespace
- 数据层需要提供通用的处理能力,比如对某些字段的运算,然后得出另外一个字段的值等
- ORM 能力
再看看我们的最强竞品,teambition,他们的方案:
teambition-sdk: https://github.com/teambition/teambition-sdk (opens new window)
从上面的思考,提取一些技术关键词:
实时同步
websocket
强缓存
离线 -> 需要 localstorage 或者 indexedDb 来支持
视图框架无关 ->应该尽量通用,如果我们有同学愿意尝试其他视图框架,我们的数据层也能满足
数据流 ->流式编程,需要支持 RxJs
独立维护
ORM ->全称是 Object Relational Map 对象关系映射,我们之前用的 Backbone-relational 插件,以及我之前给大家推荐过的 vuex-orm,都属于 ORM 工具,支持一对一,一对多这种关系管理
数据库 -> 需要有数据库的基本概念,支持索引,排序,查询,表等等
类型系统 -> 有完整的 Typescript 支持方案
共享
接口统一
通用处理能力
通过上面的思考,我慢慢明白了我要设计一个什么样的数据层
# 技术选型
我先把我选中的框架/库/插件列出来,然后再解释为什么要选:
数据库:RxDB
语言:Typescript
Vue 插件:vue-rx
# 数据库选型
在做数据库选型的时候,有很多备选方案: vuex + vuex-orm, lokijs, pouchDB, RxDB
我最开始思考的时候,其实是考虑的 vuex + vuex-orm 的方案,因为 vuex-orm 给 vuex 增加了 ORM 能力,查询接口也很友好,但是在逐渐深入思考过程中,我发现它并不合适,主要有这么两点:
- 一个 Vue 应用中,只能有一个 vuex-orm 的 database,但是我们采用了微应用架构,难免会有子应用想要有自己独立的数据库的需求
- vuex-orm 和 vue 是严重耦合的,如果我们要基于 vuex-orm 开发数据层,不好做到独立维护,也不好做到框架无关
然后是 lokijs 和 pouchDB
lokijs 是我之前做新编辑器的后台的时候就在用,用来维护一个客户端连接池,方便后台统计实时在线人数等客户端信息,而且 lokijs 也支持简单的数据库能力,比如索引啊什么的,类 mongodb 的查询方法也非常友好。我甚至还想过 vuex-orm + lokijs 的方案,但是发现 vuex-orm 官方并没有给出对应的插件,只有一个开发者自己维护了一个插件,但是好像不完善,也没人用。后来还是放弃了 lokijs,理由主要是:
- 对 rxjs 支持不友好
- 没有插件系统,不方便扩展
- 源码不是 es6 也不是 typescript 写的,如果以后我们要改它的源码,会有点麻烦
pouchDB,我很久之前就在关注 pouchDB,当时是知道 pouchDB 支持 CouchDB,可以非常方便的实现前端本地数据库和线上数据库的同步,不用后台开发人员写接口了。而且 pouchDB 提供非常友好的查询接口,支持的功能也特别多,各种本地存储/内存任你选,然后 pouchDB 就成了我的首选,我就想,只要找到 pouchDB 支持 RxJs 的插件,就完美了。
然后在搜索 pouchDB + RxJs 的时候,结果搜出了 RxDB,通读了两遍 RxDB 的文档,发现真是完美,完全满足我们的需求
我们再回到前面我列出来的需求,来对比 RxDB,
会发现真的太符合了,很像是我们先选中了 RxDB,再来决定的我们的需求一样,但其实,真的不是,RxDB 就是这么符合
# 在 Vue 的应用
- 类型提示,自动补全
- vue-rx,增加对 RxJs 的支持
# 复杂度
rxjs 的复杂度
rxjs 真的很复杂,复杂到我都觉得它很难学,很难懂
rxdb 的复杂度
typescript 的复杂度
自我感觉 ts 的复杂度会比 rxjs 低
rxjs 和 ts 应该会是我们这次重构引入的最复杂的技术
# 群众的意见
# 参考
RxDB 官网:https://rxdb.info/ (opens new window)
teambition-sdk: https://github.com/teambition/teambition-sdk (opens new window)
徐飞写的几篇关于单页应用数据管理的思考:https://github.com/xufei/blog/issues (opens new window)