这里我讲一下响应式编程(Reactive Programming)是如何将异步编程推到一个全新高度的。

异步编程真的很难

大多数有关响应式编程的演讲和文章都是在展示Reactive框架如何好如何惊人,给出一些在非常复杂的情况下,只需几行代码就可以搞定的例子。例子么?我这里有一段基于RxSwift的聊天程序的代码

socket.rx_event
.filter({ $0.event == "newMessage" && $0.items?.count > 0})
.map({ Array($0.items!) })
.subscribeNext { data in
let username = data[0]["username"] as? String ?? "unknown"
let text = data[0]["message"] as? String ?? "invalid text"
let message = JSQMessage(senderId: username, displayName: username, text: text)
self.messages += [message]
self.finishSendingMessage()
}.addDisposableTo(disposeBag)

这段代码展示了socket事件是如何被过滤和处理,以显示某个特定的用户在聊天中发送的消息的。
经典的方法可能会以类似下面的代码作为结束:

dispatch_async(dispatch_get_global_queue()) {

         let socketData = self.loadDataFromSocket()
let data = self.parseData(data) dispatch_async(dispatch_get_main_queue()) {
let username = data[0]["username"] as? String ?? "unknown"
let text = data[0]["message"] as? String ?? "invalid text"
let message = JSQMessage(senderId: username, displayName: username, text: text)
self.messages += [message]
self.finishSendingMessage()
}
}

这就是所谓的“回调地狱”,代码难以阅读和维护。但是除了真的很难阅读外,回调为什么这么不好呢?

同步变得痛苦

同步编程不仅仅是在一个单独的线程中运行任务或者执行计算,在某些时候,我们需要在多个线程中同步数值,而最常见的解决方法就是添加锁。一旦锁被引入,代码的复杂性就至少提高了一个数量级,而且又引入了一个新问题:不可预测性。

在计算方面,代码现在变得不可预测。当一个单一线程被调度时,以及假如我们访问一个预期的单一(已上锁的)属性值时,没有办法可以确定地知道我们是否会丢掉值或者正在处理和之前相同的值。

那么异步编程的真正困难是什么呢?答案是同步。听起来很有意思,但这是真的。

开始使用响应式方法

响应式编程不是我们很多人所想的那样是一个年轻的概念,这一点很重要。它的起源可以追溯到1969年,计算机科学的传奇人物Alan Kay在犹他大学的那篇名为“The Reactive Engine”的博士学位论文。但我不是在这里给大家上历史课的,考虑到有些概念听起来很好,实验起来却没那么好用,所以让我们看看响应式编程在处理同步代码时所体现出的价值。

Rx的世界中,最根本的部分是观察者模式(Observer pattern)和迭代器模式(Iterator pattern)的结合,两者都是众所周知的模式,而且在编写软件时被广泛用于处理一些特定的行为。观察者模式和迭代器模式,这两者是相互作用的,在两种情况下的计算的都是从生产者中取出的值。对于迭代器模式,只要他们是可用的,我们就可以获取值,对于观察者模式,我们是在生产者给所有具体的观察者发出通知后,从中获取数据去处理值。获取绝对是一个很好的既定具体解决方案,只要一切都是在同一线程中处理的,它就能很好地起作用。当数据被获取出来,进行一步的处理时会发生什么呢?好了,此时我们添加的锁开始发挥作用了,事情很快就难办了。

设想情景

我们设想一下,有一个非常好的应用,已经准备好了在几天内发布,但是在最后的测试中,在某些情况下,一些死锁和征用条件产生了,而应用的崩溃是随机的,只有足够的数据才能够去确定这个问题。时间是有限的,问题在可能出现的地方比预期的还要发生得更快,但是解决方案或许不能那么简单和快速地开发和部署出来。首先要记住的是,一旦采用了锁定策略,那么整个代码的运行速度都会减慢,同时异步编程的不可预测性也会影响到一般应用程序的性能。也有可能会有数量级的增长放缓,我们可以得到的结论是:这是不可接受的。

什么是响应式

响应式是一种设计,获取数据是一个绝对的东西,可能很难在很短的一段时间内调整,所以一个解决方案是翻转该行为,即为什么不能让资源自己把值推送给一个用户/消费者,而是我们去从一个资源获取呢?这就是Rx具体的内容,即推送数据给被生产者订阅了的实例。我们在某些地方产生数据,然后根据需求将数据推送给用户并进行处理。

观察者 + 迭代器 + 推送 = 可观测的(Observable)实体

 

Rx背后的数学很简单,两个非常确定的实体,结合不同的交互模型,成为了一个可观测的实体的根基。这就是革命发生的地方,结合旧的,既定的概念,以一定的方式创建和模拟一个强大的抽象概念,来帮助处理异步编程,而不用去冒着项目在最后一周挂掉的危险。

这个数学公式的结果是一个叫做可观测的实体,这个对象负责处理原始数据,并在必要时将值推送给用户。用户可以扮演多种角色,它们可以成为别的连锁的可观测实体、操作者或者仅仅是回调。Rx是非常基本的,但也是非常强大的抽象概念。

声明

使用可观测实体的方法要求初始化可观测实体时声明逻辑,这意味着我们的代码变得更加紧凑,而且通常被限制在view Controller的初始化方法中。在这个的RxChat的例子中,逻辑的大部分都是在viewDidLoad的函数中声明的:

 override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib. self.setup() user
.distinctUntilChanged()
.subscribeNext() { username in
self.senderId = username
self.senderDisplayName = username
self.socket.emit("addUser", withItems:[username])
}.addDisposableTo(disposeBag) socket.rx_event
.filter({ $0.event == "connect"})
.map({ _ in return () })
.subscribeNext { _ in
self.title = "RxChat (Connected)"
}.addDisposableTo(disposeBag) // [...]
}

这种方法也被称为声明式编程(Declarative Programming),可以帮助我们有效减少潜在bug的数量,也使得在使用MVVM或者类似的模式时所写出的代码让人眼前一亮。

现在做什么呢?

一般来说,学习Rx或响应式编程就像学习一门新的语言(不是指编程语言),步骤是非常相似的,我们在最初的阶段学习基本语法和常用句子,然后学习规则和语义,最后我们能够说出某些甚至最难的话题时,我们就掌握了这门语言。

为了持续学习,我建议读者阅读以下资料:

总结

这篇文章可能看起来非常短(事实上,我也打算把它写这么短),但是它写出了我心中关于Rx的基础知识的理解。大部分的文章和演讲都是在外围讨论如何使用它,为什么要用它,但是很少有人讨论为什么Rx是这样的强大,为什么它可以这么短。Rx的面具下没有魔法,RxSwift所用到的都是一些既有的东西,它只是建立概念,用聪明的方法将这些东西粘在一起,来创建一个强大的异步计算的抽象概念。不要再花时间给你的异步软件写同步策略了,把时间花在写逻辑上吧。

转载自:http://www.infoq.com/cn/articles/swift-responsive-programming-revolution?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=articles_link&utm_content=link_text

Swift 响应式编程 浅析的更多相关文章

  1. iOS开发--Swift RAC响应式编程初探

    时间不是很充足, 先少说点, RAC的好处是响应式编程, 不需要自己去设置代理委托, target, 而是主要以信息流(signal), block为主, 看到这里激动吧, 它可以帮你监听你的事件, ...

  2. [译] Swift 的响应式编程

    原文  https://github.com/bboyfeiyu/iOS-tech-frontier/blob/master/issue-3/Swift的响应式编程.md 原文链接 : Reactiv ...

  3. iOS开发--Swift RAC响应式编程

    时间不是很充足, 先少说点, RAC的好处是响应式编程, 不需要自己去设置代理委托, target, 而是主要以信息流(signal), block为主, 看到这里激动吧, 它可以帮你监听你的事件, ...

  4. iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好

    转载: iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好 内容来自stack overflow的一个回答:ReactiveCocoa vs RxSwift – pros an ...

  5. 深入浅出-iOS函数式编程的实现 && 响应式编程概念

    简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 配图 ...

  6. [HMLY]11.iOS函数式编程的实现&&响应式编程概念

    简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 作为一 ...

  7. 响应式编程系列(一):什么是响应式编程?reactor入门

    响应式编程 系列文章目录 (一)什么是响应式编程?reactor入门 (二)Flux入门学习:流的概念,特性和基本操作 (三)Flux深入学习:流的高级特性和进阶用法 (四)reactor-core响 ...

  8. ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一!

    简介 项目主页: ReactiveCocoa 实例下载: https://github.com/ios122/ios122 简评: 最受欢迎,最有价值的iOS响应式编程库,没有之一!iOS MVVM模 ...

  9. iOS-函数式编程 && 响应式编程概念

    作为一个iOS developer,那么你一定用过Masnory / SnapKit: Masonry是一个OC开发中,非常好用的自动布局的第三方框架: SnapKit是Masonry团队打造的swi ...

随机推荐

  1. Python之生产者&、消费者模型

    多线程中的生产者和消费者模型: 生产者和消费者可以用多线程实现,它们通过Queue队列进行通信. import time,random import Queue,threading q = Queue ...

  2. 实现类似QQ自拍头像的功能(demo源码)

    在很多软件系统中,都允许用户设置自己的头像,甚至可以直接使用摄像头照相作为自己的头像,就像QQ的自拍头像功能一样. 这种功能是如何实现的了?最直接的,我们可以使用Windows提供的VFW技术或Dir ...

  3. 洛谷-哥德巴赫猜想(升级版)-BOSS战-入门综合练习1

    题目背景 Background 1742年6月7日哥德巴赫写信给当时的大数学家欧拉,正式提出了以下的猜想:任何一个大于9的奇数都可以表示成3个质数之和.质数是指除了1和本身之外没有其他约数的数,如2和 ...

  4. B - 小Y上学记——小Y的玩偶

    B - 小Y上学记——小Y的玩偶 Time Limit: 2000/1000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/Others) ...

  5. JS 经典代码段总结 start from 2016-08-22

    1.for(var i = 0, max = myArray.length; i < max ; i++){ //用myArrayy[i]来做点什么 } 用max存储myArray的长度,防止每 ...

  6. subnetting and the subnet mask

    原文:https://www.techopedia.com/6/28587/internet/8-steps-to-understanding-ip-subnetting/5 Step 4 - Sub ...

  7. maven下载,安装与eclipse中maven配置

    1.maven下载.安装与环境变量配置 http://blog.csdn.net/jiuqiyuliang/article/details/45390313 2.Eclipse中maven的配置 ht ...

  8. (译)UEFI 启动:实际工作原理

    本文是我翻译自国外技术博客的一篇文章,其中讲述了 UEFI 的一些基本概念和细节. 本文的原始链接位于: https://www.happyassassin.net/2014/01/25/uefi-b ...

  9. 当引用了Properties.Settings后,如果执行的时候,出现"配置系统无法初始化" 或者 某某节点不正确

    自定义了一个 PowerConfig命名空间   PowerSettings.Settings 然后一个exe,引用了该dll,在app.cinfig里增加了配置项 <applicationSe ...

  10. VBS脚本实例

    一.一键升级哨位台核心板程序脚本. ############################################################ Set ws=WScript.Create ...