ascoders / blog

博客
263 stars 0 forks source link

精读《单页应用的数据流方案探索》 #18

Open ascoders opened 7 years ago

ascoders commented 7 years ago

1 引言

前几期精读了前端模块化、语法相关的文章,这次讨论另一个举足轻重的话题:数据流。 数据流在前端的地位与工程化、可视化、组件化是一样重要的,没有好的数据流框架与思想的指导,业务代码长期肯定倾向于不可维护的状态,当项目不断增加功能后,管理数据变得更加重要。

早期前端是没有数据流概念的,因为前端非常薄,每个页面只要展示请求数据,不需要数据流管理。

随着前端越来越复杂,框架越来越内聚,数据流方案由分到合,由合又到了分,如今数据流逐渐从框架中解绑,形成了一套通用体系,供各个框架使用。

虽然数据流框架很多,但基本上可以分为 双向数据流党单向数据流党响应式数据流党,分别以 MobxReduxRxjs 为代表呈现三国鼎立之状,顺带一提,对 css 而言也有 css in js 和纯 css党 势均力敌,前端真是不让人省心啊。这次我们来看看民工叔徐飞在 QConf 分享的主题:单页应用的数据流方案探索

2 内容概要

文中主要介绍了响应式编程理念,提到的观点,主要有:

  1. Reactive 数据封装
  2. 数据源,数据变更的归一
  3. 局部与全局状态的归一
  4. 分形思想
  5. action 分散执行
  6. app级别数据处理,推荐前端 Orm

整体来看,核心思路是推荐组件内部完成数据流的处理,不用关心使用了 Redux Mobx 或者 Rxjs,也不用关心这些库是否有全局管理的野心,如果全局管理那就挂载到全局,但组件内部还是局部管理。

最后谈到了 Rxjsxstream 响应式数据流的优势,但并未放出框架,仅仅指点了思想,让一些读者心里痒痒。但现在太多”技术大牛“把”业界会议“当成了打广告,或者工作汇报的机会,所谓授人以鱼不如授人以渔,这篇文章卓尔不群。

3 精读

一切技术都要看业务场景,民工叔的 单页应用数据流方案 解决的是重前端的复杂业务场景,虽然现在前端几乎全部单页化,但单页也不能代表业务数据流是复杂的,比如偏数据展示型的中台单页应用就不适合使用这套方案。

此文讨论的是纯数据流方案,与 Dom 结合的方案可以参考 cyclejs,但这个库主要搭建了 Reactive -> Dom 的桥梁,使用起来还要参考此文的思路。

3.1 响应式数据流是最好的方案吗?

我认为前端数据流方案迭代至今,并不存在比如:面向对象 -> 函数式 -> 响应式,这种进化链路,不同业务场景下都有各自优势。

面向对象

以 Mobx 为代表,轻前端用的较多,因为复杂度集中在后端,前端做好数据展示即可,那么直接拥抱 js 这种基于对象的语言,结合原生 Map Proxy Reflect 将副作用进行到底,开发速度快得飞起。

数据存储方式按照视图形态来,因为视图之间几乎毫无关联,而且特别是数据产品,后端数据量巨大,把数据处理过程搬到前端是不可能的(为了推导出一个视图形态数据,需要动辄几GB的原始数据运算,存储和性能都不适合在前端做)。

函数式

以 Haskell 为代表,金融行业用的比较多,可能原因是金融对数据正确性非常敏感,不仅函数式适合分布式计算,更重要的是无副作用让数据计算更安全可靠。

个人认为最重要的原因是,金融行业本来很少有副作用,像前端天天与 Dom 打交道的,副作用完全逃不了。

响应式

以 Rxjs 为代表,重前端更适合使用。对于 React native 等 App 级别的开发,考虑到数据一致性(比如修改昵称后回退到文章详情,需同步作者修改后的昵称),优先考虑原始类型存储,更适合抽象出前端 Orm 作为数据源。

其实 Orm 作为数据源,面向对象也很适合,但响应式编程的高层次抽象,使其对数据源、数据变动的依赖可插拔,中等规模使用大对象作为数据源,App 级别使用 Orm 作为数据源,因地制宜。

3.2 分形思想

分形思想即充血组件的升级版,特点是同时支持贫血组件的被外部控制能力。

分形的优点

分形保证了两点:

  1. 组件和数据流融为整体,与外部数据流隔离,甚至将数据处理也融合在数据管道中,便于调试。
  2. 便于组件复用,因为数据流作为组件的一部分。

如果结合文中的 本地状态 概念,局部数据也放在全局,就出现了第三点好处:

  1. 创建局部数据等于创建了全局数据,这样代码调试可局部,可整体,更加灵活。

本地状态 可以参考 dva 框架的设计,如果没有全局 Redux 就创建一个,否则就挂载到全局 Redux 上。

分形的缺点

对于聊天室或者在线IDE等,全局数据居多,很多交叉绑定的情况,就不适合分形思想,反而纯 Redux 思想更合适。

3.3 数据形态,是原始数据还是视图数据?

我认为这也是分业务场景,文章提到不应该太偏向视图结构数据,是有道理的,意思是说,在适合原始结构数据时,就不要倾向于视图结构数据了。但有必要补充一下,在后端做了大量工作的中台场景,前端数据层非常薄,同时拿到的数据也是后端服务集群计算后的离线数据,显然原始数据结构不可能放在前端,这时候就不要使用原始数据存储了。

3.4 从原始数据到视图数据的处理过程放在哪

文中推荐放在 View 中处理,因为考虑到不想增加额外的 Store,但不知道这个 Store 是否包含组件局部的 Store。业务组件推荐使用内部数据流操作,但最终还是会将视图数据存在全局 Store 中,只是对组件而言,是局部的,对项目而言是全局的,而且这样对特定的情况,比如其他组件复用数据变更的监听可以支持到。

总结

我们到头来还是没有提供一个完美的解决方案,但提供了一个完整的思路,即在不同场景下,如何选择最合适的数据流方案。

最后,不要盲目选型,就像上面提到的,这套方案对复杂场景非常棒,但也许你的业务完全不适合。不要纠结于文中为何没有给出系统化解决方案的 Coding 库,我们需要了解响应式数据流的优势,同时要看清自己的业务场景,打造一套合适的数据流方案。

最后的最后,如有不错的数据流方案,解决了特定场景的痛点,欢迎留言。

如果你想参与讨论,请点击这里,每周都有新的主题,每周五发布。