原文地址:http://www.moye.me/2016/05/31/learning_rxjs_part_one_preliminary/

引子

新手们在异步编程里跌倒时,永远会有这么一个经典问题:怎么在一次异步调用里return一个结果啊?

老司机说要用回调函数,然后有条件判断的嵌套回调(回调地狱)问题来了;

老司机推荐用事件,然后异步流程里有顺序依赖;

老司机推荐用Promise,然后有顺序依赖的流程里,居然还想订阅事件;

老司机建议试试协程,谁知对方想要合并两个异步调用;

……

以上,是异步编程里要面对的一些难题,也是ReactiveX API 所致力解决的

是什么

知道有 ReactiveX 这么一回事, 源于一位巨硬铁粉的安利演示:Reactive LINQ 加持的C#,简洁且颇具表达力;随后,便是万众瞩目的 Angular 2,这货的标配大礼包里就有RxJS,比比皆是的 api.invocation.map(...).subscribe(fn, fn, fn) 片断,让jQuery青年们一头雾水。

落伍总是不好的,林子里的鸟都在讨论FRP时,我们也要跟上:

ReactiveX是Reactive Extensions的缩写,一般简写为Rx,最初是LINQ的一个扩展,由微软的架构师Erik Meijer领导的团队开发,在2012年11月开源,Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,Rx库支持.NET、JavaScript和C++,Rx近几年越来越流行了,现在已经支持几乎全部的流行编程语言了,Rx的大部分语言库由ReactiveX这个组织负责维护,比较流行的有RxJava/RxJS/Rx.NET,社区网站是 reactivex.io

概念

ReactiveX 的自述是  “An API for asynchronous programming with observable streams”,那么,什么是Observable,什么又是Stream呢?

Stream

Erik Meijer发过一篇paper: “Your Mouse Is a Database”,大概意思是说,用户的鼠标点击其实是一个无穷而实时的事件序列,可以将其视为一个与时间线相关的数据流,我们 可以查询并操作这个数据流,在它可用时(或者等待数据流可用):

在 Rx 编程中,任何数据都可以被表达为数据流的形式,我们要做的是,对数据流进行订阅、查询、过滤、打平、归并等各种操作。

由于是对 数据流序列 进行订阅(观察),Rx 的编程模型实际是基于 Observer pattern 和 Iterator pattern 这两种设计模式构建的。

Observable

在Rx中,Observable就是一个序列,它按序对订阅方(subscriber)进行值的推送,遵循一套 “Don’t call us; we’ll call you.” 的基本法。

基于 Observable 的模式, 和传统的 Observer pattern有两点本质的不同:

  1. Observable 只在至少有一个订阅者时,数据才开始流动
  2. 在数据流结束(iterator 不再hasNext)时,Observable会发出通知(onCompleted)

怎么用

程序员们大都被调教成了马基雅维利主义者:“整点有用的”。所以,还是来看看RxJS怎么用吧:

场景

我有一个C类局域网,想要挨个ping一下网络内的设备,看看哪些IP在线(并不知道DHCP的客户端列表,所以得从 xxx.xxx.xxx.2 ping到 xxx.xxx.xxx.254)

思路

很明显,ping 是一个异步的操作,这里大概有 254 - 2 = 252 个异步操作,难点不在于异步,而在于流程控制,在RxJS 里,可以很方便的把Observable源进行归并(merge),从而让异步数据流可控且有序

RxJS方案

依赖
"dependencies": {
"ping": "^0.1.10",
"ramda": "^0.21.0",
"rx": "^4.1.0",
}
代码
var Rx = require('rx')
var R = require('ramda')
var pingCommand = require('ping') var config = {
timeout: 10, // 超时为10秒
extra: ["-i 2"], // 每次发包间隔时长
}
function promisablePing(host) {
return new Promise((resolve, reject) => {
pingCommand.sys.probe(host
, isAlive => isAlive ? resolve(host) : reject(`${host}: unreachable.`)
, config)
})
}
function ping(host) {
return Rx.Observable.create(observer => {
return promisablePing(host)
.then(host => observer.onNext(host))
.then(_ => observer.onCompleted())
.catch(err => observer.onError(err))
})
} var tasks = R.range(2, 254).map(i => ping(`192.168.50.${i}`))
Rx.Observable
.merge(...tasks)
.subscribe(
host => console.log(`pong: ${host}`),
err => console.error(err)
)

说明

代码足够简单,值得说明的是:

    1. Rx.Observable.create会创建一个Observable对象,对它进行订阅的观察者即create函数中回调的入值observer,观察者有三个方法:onNext, onCompleted, and onError:
      1. onNext :在序列推送一个新值时被调用,对应到观察者的subscribe第一个函参
      2. onCompleted:序列中已无值可用,对应到观察者的subscribe第三个函参
      3. onError:序列中发生了错误,对应到观察者的subscribe第二个函参
    2. merge合并后的操作流,是一个对IP在:192.168.50.2 - 254 范围内的设备进行Ping的操作序列,但是Observable有一个特点,就是任何时候触发了 错误回调(即Rx.Observable.create创建那个的观察者,进行了onError通知,从而触发了消费者提供给subscribe函数第二个参数)那么整个Observable序列就此结束。比如,我的C类子网就两台设备在线:xxx.xxx.xxx..100 和 xxx.xxx.xxx.200,然后 xxx.xxx.xxx.2 在10秒后超时报错,那这条Observable时间线看起来就是这样的:
      BEGIN-> .100-.200---------------------[.2 error] ->END
    3. Ramda 是一个优秀的函数式JS库,当然,用成了lodash也不坏

小结

以上,只是冰山一角,下回,想聊聊基于RxJS的Web框架:Cycle.js

更多文章请移步我的blog新地址: http://www.moye.me/

学习RxJS: 导入的更多相关文章

  1. Android学习:导入工程时报错The import android cannot be resolved

    今天在导入别人的工程时,出现了一个这个问题The import android cannot be resolved 就是找不到import android.support.v7.app.Action ...

  2. JS做深度学习2——导入训练模型

    JS做深度学习2--导入训练模型 改进项目 前段时间,我做了个RNN预测金融数据的毕业设计(华尔街),当时TensorFlow.js还没有发布,我不得已使用了keras对数据进行了训练,并且拟合好了不 ...

  3. VB6.0编程笔记——(2)开发环境准备&学习前导入

    工欲善其事必先利其器,着手开始学习写代码之前,我们需要先准备好需要用到的工具.这篇文章会教大家部署好环境,同时会告知前期我们需要知道的一点内容(可以不用特别理解,只要记住用法就行,后续会深入展开介绍) ...

  4. MySQL学习记录(导入Excel表到数据库,并筛选条件输出)

    附上:重置mysql账号密码方法 ubuntu系统下mysql重置密码和修改密码操作 - skh2015java的博客 - CSDN博客(改完重启,登录mysql要root/sudo权限) Cento ...

  5. 吴裕雄--天生自然 R语言开发学习:导入数据

    2.3.6 导入 SPSS 数据 IBM SPSS数据集可以通过foreign包中的函数read.spss()导入到R中,也可以使用Hmisc 包中的spss.get()函数.函数spss.get() ...

  6. PV3D学习笔记-导入DAE模型

      网上关于PV3D导入DAE模型的例子都非常多,可惜我研究了半天,一个都没成功,或者是破面问题,或者是贴图不显示,再或者贴图乱掉了.今天晚上终于搞定,心得发上来. 制作模型的软件是SketchUp ...

  7. python学习笔记--导入tab键自动补全功能的配置

    今天开始学习Python,必须配置tab键补全功能 1.首先我们需要查看python的安装路径 [root@abc ~]# python Python 2.6.6 (r266:84292, Jan 2 ...

  8. python 入门学习---模块导入三种方式及中文凝视

    Python 有三种模块导入函数 1. 使用import 导入模块 import modname : 模块是指一个能够交互使用,或者从还有一Python 程序訪问的代码段.仅仅要导入了一个模块,就能够 ...

  9. Solr学习笔记——导入JSON数据

    1.导入JSON数据的方式有两种,一种是在web管理界面中导入,另一种是使用curl命令来导入 curl http://localhost:8983/solr/baikeperson/update/j ...

随机推荐

  1. JavaScript 基础第九天(DOM第三天)

    一.引言 我们昨天介绍了很多的概念以及大部分我们可以在工作中用到的事件,那么今天我们将运用这些知识做一些效果! 二.导入 今天的内容以实例为主. 三.重点内容 祝愿墙的简单构建: 首先我将介绍出本次实 ...

  2. Git凭证存储(简单易懂,一学就会,认真看)

    今天给自己提了一个问题,当我们在github.com或者gitlab上面新建仓库,并克隆到本地,首次使用的时候,会被问及用户名密码,但是这两个信息存在哪里呢? 带着这个问题,我开始搜索,并在<P ...

  3. 从MySQL5.7.6开始,安装MySQL提示“请键入 NET HELPMSG 3534 以获得更多的帮助”的解决办法

    今天安装MySQL提示如下错误: ----------------------------------------------------------------------------------- ...

  4. 开始VS 2012中LightSwitch系列的第3部分:我该选择哪一个屏幕模板

    [原文发表地址]  Beginning LightSwitch in VS 2012 Part 3: Screen Templates, Which One Do I Choose? [原文发表时间] ...

  5. [.NET领域驱动设计实战系列]专题五:网上书店规约模式、工作单元模式的引入以及购物车的实现

    一.前言 在前面2篇博文中,我分别介绍了规约模式和工作单元模式,有了前面2篇博文的铺垫之后,下面就具体看看如何把这两种模式引入到之前的网上书店案例里. 二.规约模式的引入 在第三专题我们已经详细介绍了 ...

  6. 超出TCP连接端口数限制(MaxUserPort)引起的服务器问题

    昨天2台Windows Server 2012服务器出现奇怪的问题,自己竟然连不上自己的本机80端口,telnet 127.0.0.1 80也连不上,而更奇怪的是其它服务器可以连接到这2台服务器的80 ...

  7. IO完成端口

    从MSDN中翻译了IO完成端口的文章,不得不说翻译的很烂,英语需要继续提高啊... 在一个多处理器系统上,IO完成端口提供一个非常高效的线程模型来处理多个异步IO请求.当一个进程创建了一个IO完成端口 ...

  8. js实现DOM结构

    /* 编写一段js脚本生成下面的DOM结构.要求使用标准的DOM方法或属性 <div id='example'> <p class='slogan'>淘,你喜欢</p&g ...

  9. 【译】用Fragment解决屏幕旋转(状态发生变化)状态不能保持的问题

    这篇文章解决了在StackOverflow上一个经常被提到的问题. 在配置发生变化(Configuration changs)时,什么是最好的保存活动对象方法,比如运行中的线程,Sockets,Asy ...

  10. .NET在线培训 | C#在线培训 | .NET培训 | 最课程培训

    最课程(www.zuikc.com) 软件开发培训,在线软件培训的创新者!我们的创新在于: 1:一次购买,终身服务.每个最课程学员都会分配一位专职教师及一位监管教师,点对点跟进课程进度,直到您学会课程 ...