程序猿打Boss高级技能——Rx

对于函数响应式编程(Functional Reactive Programming),本人第一次接触到是在两年前,当时看到ReactiveCocoa框架对它一时不来电。直到最近抽时间学习了一下Swift 语言,对Swift版本的FRP 框架RxSwift 进行了深入的学习。

1、背景

我们可爱的程序猿在开发的过程中,因为业务需求,在数据流处理或者是用户操作的各个阶段,总是避免不了创建许多临时状态,用来判别、疏导程序的执行顺序。其中,在开发异步程序的时候,这种临时状态所带来的问题尤为明显。

举个例子:我们经常碰到像“键盘精灵”、“搜索引擎”这类异步的搜索功能。当用户输入“0”的时候,程序就应该实时的去请求相应的结果集。这个时候,因为网络的原因数据迟迟未能返回,不过用户还在继续输入想要搜索的更加精准的字符“01”、“012”等等,每一次的输入变化逻辑上都要撤销前一次的请求,再发送请求最新的结果集。到这里还不算复杂,那么,如果当我们的请求失败的时候,就需要编写retry 重试逻辑,请求成功和失败之间的需要维护一堆的临时状态和处理逻辑。

OMG!!! These will be driving me mad. 有木有?有木有更加简单清晰一点方案来救救我吧!!!

那么下面就让我们来见证一下奇迹(Swift 代码):

其中,searchTextField 是用户输入搜索字符的TextField 控件,而searchTextField.rx_text 就好像给这个控件凿开了一个口子,当用户输入字符的时候,字符就像从这个“口子”里流出来的水一样,一滴、两滴、三滴……

这个时候,如果不对水流做一些节制,那么就白白浪费掉了。Throttle 操作函数就像在这个“口子”上装了水龙头一样——开源节流,不随意浪费“资源”。这里的意思是:每次变化都停留了300毫秒后,打开水龙头放水。

当下一次拧开水龙头放水时,如果流出来的字符和上一次一样,这个时候重复发送请求的话,其实是没有意义的。distinctUntilChanged 就是过滤去重的作用,不发送同前一次一样的请求。

flatMapLatest 的Block 中拿到了放出来的“有效”字符串,程序执行到这里才真正去发送API.getSearchResults(query) 网络请求去搜索结果集。刚才说到的失败retry 重试逻辑,在这里就只是一个简单的Operator 操作,Rx 已经帮我们处理好了如何retry。我们只需要关注搜索的结果集,对结果数据进行展示处理救OK 了。

我们知道,临时状态一多就会使我们的代码杂乱甚至难以维护。同样的业务逻辑,这么简短的几行代码,同时又帮助我们解决了常规开发思维中碰到的许多麻烦,而且它没有任何附加的临时状态。

“这是什么鬼,本来要写五百行代码,现在十行都不到,简直就是无视我的KPI啊!!!”。

这就是传说中的函数响应式编程(Functional Reactive Programming),市面上常用的语言都拥有它的身影(RxJS,RxJava,RxCpp,RxPhp,Rx.Net等等),作为一个编程思想的集合体,官方称为ReactiveX(官网:http://reactivex.io),简称Rx。

Rx 是观察者模式(Observer Pattern)的典型应用,所有的异步信息流都可以抽象为一个可观察对象(Observable),需要使用信息流的对象抽象为观察者(Observer)。Observer 根据需要向Observable 发起订阅,即:Observable.subscribe(Observer)。当Observable 有信息到来时,来自全世界的Observer 都能够接收得到。

Rx 的目标是让异步和事件数据流操作更简单。

引用:KVO observing, async operations and streams are all unified under abstraction of sequence. This is the reason why Rx is so simple, elegant and powerful.

2、Rx的优点

1) 线程安全

数据是通过值拷贝的方式在线程中进行传递——值传递,其他线程也有自己的数据Copy,互不牵扯。好比数学中函数,指定传入的参数,也就确定了答案一样“Data in and Data out”,这也就是为什么叫做函数式的由来。

2) 代码更加简洁精炼,开发效率显著提高

正如前面的例子,简单的调用几个操作函数,简化了常规编程中许多临时状态造成的复杂逻辑,减少了大量bug的产生,是开发更加高效。第1、2点和Rx的目标吻合。

3)代替异步操作,用Rx操作函数轻松处理(转换、过滤、合并)

根据Rx异步操作的抽象概念(Observer Pattern),以下的异步操作都可以抽象成可观察对象(Observable)和观察者(Observer)。事实上,Rx已经提供了这些类型的抽象,如Swift语言中,可以参考RxCocoa框架。

代理:Delegate

回调:Block Callbacks

事件:Target Action

通知:Notifications

KVO

4) MVVM 模式最佳粘合剂,让单元测试更得心应手

我们知道MVVM 模式让视图控制器VC 的身板更加精致,VC 和VM 之间的责任边界也非常明确:VM 负责数据处理&VC 负责数据展示。

现在,Rx 和 MVVM结合在一起,除了Bug 随着临时状态大量减少外,单元测试也变的非常容易。Rx 测试框架RxTest提供了一组强大的模拟接口,可以模拟信息流,也就是可以模拟用户操作,非常方便的开发单元测试程序。

3、Rx延伸方向思考

1) 各平台接口用Rx 封装(很多平台&云服务已经对外提供了Rx 接口)

2) 使用MVVM 开发模式,场景化包装可重用VM 模块

其中1是接口级(我们已经实现),2是VM模块级(包装了业务模型,从UI分离出来)

3) 跨平台开发

用JS 开发各平台UI,使用Native 封装Rx接口(互调性能问题?耦合性高)

界面布局和信息流(RxJS)逻辑用JS实现。Native 开发渲染Render 引擎(有点类似React Native)。

4、总结

看到如此简单的几行代码就能实现原本复杂逻辑而正为之兴奋不已的时候,有没有感觉到像是获得了另一种更加强大的高级技能!!!

那么,我们静下心来捋一捋:Rx之于我们程序员的重要性在于,当PM为用户场景化交互进行激烈地讨(si)论(bi)时,我们程序员(PG)又有了一种可选技能,而且“已然”对各种场景有了最有效的技能应对——拥抱变化,成竹在胸

5、附录

附上RxSwift中常用的一种可观察对象(Just)源码CSequence图,帮助理解源代码。

蓝色背景的是继承关系的Protocol 或父类,黄色背景的是实体对象类(左边Observable,右边Observer),当可观察对象被订阅Observable.subscribe(Observer) 时,两者之间的交互逻辑。

参考:

Rx官网:http://reactivex.io

Rx可视化工具,帮助理解各种操作函数 :http://rxmarbles.com/

Rx开源Github:https://github.com/Reactive-Extensions


本文作者:罗俊涛(点融黑帮),现任点融网高级移动iOS开发工程师。从最初的嵌入式研发到近几年金融产品研发,对金融产品有比较全面的认识。一直认为“能够专注于技术,翱翔于代码的无边天际”是一件无比幸福的事情。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 本篇文章介主要绍RxJava中操作符是以函数作为基本单位,与响应式编程作为结合使用的,对什么是操作、操作符都有哪些...
    嘎啦果安卓兽阅读 2,784评论 0 10
  • 引言 RxAndroid是一个开发库、是一种代码风格、也是一种思维方式。 正如标题所言,RxAndroid的特点是...
    蓝灰_q阅读 24,488评论 4 106
  • 那些相处时 让我们感到舒服的人 他们的微笑令人陶醉 举止让人温暖 没有过不去的坎 没有渡不过的劫 有些人的善意 就...
    刘思琳阅读 239评论 0 2