Markdown测试


title: RxJS简介
date: 2017-08-01 09:45:33
tags: [JavaScript, RxJS]


摘要

RxJS是ReactiveX的JavaScript实现,除此之外还有RxJava、Rx.Net、RxSwift等,ReactiveX提供了一系列的数据流组合和控制能力。RxJS被广泛的运用在Angular中,本文做一些简单的资料搬运和介绍。

核心概念

Reactive Programming: 一种面向数据流(Data Flows)和变化传播(the Propagation of Change)的编程范式。
ReactiveX(Reactive Extensions): 简写Rx,由微软开发维护的基于Reactive Programming实现的一个工具库集合,Rx系列集合了观察者模式、迭代器模式和函数式编程,是响应式编程的优秀实践。

面向变化传播的示例与解释:

对下面语句
<pre><code>a = b + c</code></pre>
Imperative Programming: 一个赋值过程,赋值完成即结束,a和b、c的变化再没有关联。
Reactive Programming: 当b或者c发生变化时,a也会跟着发生变化。

在我们熟悉的MVVM中,也存在Model => View, View => Model这样的变化关系,当View有数据绑定时,View Model会更新Model,当Model变化时,Model会通知View Model、View Model进而通知View更新。前端的MVVM框架也体现了面向变化传播的思想。

面向数据流的示例与解释:

监听一系列的事件流,比如用户触发的事件、网络请求的响应、定时器、MutationObserver等等等等,我们通过RxJs的一系列方法将这一系列事件流转化为数据流,对数据流进行进行过滤、合并等各种你需要的操作后响应事件流的回调,这个过程就属于面向数据流的编程。

Observable

Observable将异步数据转化为数据流,转化后的Observable对象相当于数据源,我们后面的操作都在Observable对象的基础上进行,Observable是观察者模型中的被观察者。
{% codeblock lang:js %}
const button = document.querySelector('#js-button');
const buttonClick$ = Rx.Observable.fromEvent(button, 'click');
buttonClick$.subscribe(() => console.log('clicked'));
{% endcodeblock %}

Operator

Observable对象的操作者,可以对Observable对象进行过滤、合并、转化等操作,大多数operator会在操作完成后返回一个新的Observable对象供下一个operator进行处理,方便的进行链式调用。
{% codeblock lang:js %}
const myObservable = observable$.debounceTime(500).first()
{% endcodeblock %}

Observer

观察者模型中的观察者,当Observable被subscribe函数订阅时,subscribe期待一个observer来进行响应。
{% codeblock lang:js %}
observable$.subscribe(observer)
{% endcodeblock %}

Subscription

Observable被subscribe函数订阅时后返回的Subscription实例, 订阅对象有一个重要的方法:unsubscribe,用来释放资源或者取消Overvable对象的执行。
{% codeblock lang:js %}
const observable$ = Rx.Observable.interval(1000);
const subscription = observable$.subscribe(x => console.log(x));
subscription.unsubscribe();
{% endcodeblock %}
可以对单个订阅对象unsubscribe, 也可以对多个订阅对象unsubscribe,方法是将一个订阅对象add到另一个订阅中(remove方法从订阅对象中移出add进的订阅对象)

{% codeblock lang:js %}
const observable1$ = Rx.Observable.interval(200);
const observable2$ = Rx.Observable.interval(300);
const subscription1 = observable1$.subscribe(x => console.log(observable1:${x}));
const subscription2 = observable2$.subscribe(x => console.log(observable2:${x}));
subscription1.add(subscription2);
// 取消全部订阅
setTimeout(() => {
subscription1.unsubscribe();
}, 1000);
{% endcodeblock %}

Subject

Subject是一种特殊的Observable,它允许值被多个观察者执行,类似于EventEmitter的数据结构。它既是被观察者也是观察者。

作为被观察者多次被订阅

{% codeblock lang:js %}
const subject = new Rx.Subject();
subject.subscribe({
next: (value) => console.log(observerA:${value});
});
subject.subscribe({
next: (value) => console.log(observerB:${value});
});
subject.next(1);
subject.next(2);

// 打印结果
// observerA: 1
// observerB: 1
// observerA: 2
// observerB: 2
{% endcodeblock %}

作为观察者成为subscribe的参数

{% codeblock lang:js %}
const subject = new Rx.Subject();
subject.subscribe({
next: (value) => console.log(observerA:${value});
});
subject.subscribe({
next: (value) => console.log(observerB:${value});
});
const observable$ = Rx.Observable.from([1, 2, 3]);
// subject作为观察者
observable$.subscribe(subject);

// 打印结果
// observerA: 1
// observerB: 1
// observerA: 2
// observerB: 2
// observerA: 3
// observerB: 3
{% endcodeblock %}

Scheduler

调度者,控制着何时启动一个订阅和何时通知被发送。
Scheduler有三个组件构成:

  • 一个调度者是一个数据结构。它知道如何根据优先级或其他标准存储和排列任务。
  • 一个调度者是一个执行上下文。它表示何处何时任务被执行(例如: immediately(立即), or in another callback mechanism(回调机制), such as setTimeout(定时器) or process.nextTick(在下一个事件轮询节点执行), or the animation frame(动画))。
  • 一个调度者具有虚拟的时钟。它通过调度器上的getter方法now()提供了“时间”的概念。 在特定调度程序上调度的任务将仅仅遵守由该时钟表示的时间。

这是一个使用observeOn操作符传递这些值的异步调度程序
{% codeblock lang:js %}
const observable$ = Rx.Observable.create(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
})
.observeOn(Rx.Scheduler.async);
console.log('just before subscribe');
observable$.subscribe({
next: x => console.log('got value ' + x),
error: err => console.error('something wrong occurred: ' + err),
complete: () => console.log('done')
});
console.log('just after subscribe');

// 打印结果
// just before subscribe
// just after subscribe
// got value 1
// got value 2
// got value 3
// done
{% endcodeblock %}

Observable的“冷”与“热”

Rx中,Observable通常实现成Hot和Cold模式,Hot模式下,Observable对象一旦创建就开始发送数据,在Cold模式下,Observable只有在被订阅后才会开始发送数据,RxJs实现的是Observable的“冷”模式。

示例代码:
{% codeblock lang:js %}
const observable$ = new Observable(observable => {
console.log('Observable Start!');
observable.next();
})
console.log('start');
observable$.subscribe();

// 打印结果
// start
// Observable Start!
{% endcodeblock %}

只有当observable被subscribe后才发送数据

Connectable模式

该模式下的Observable对象不管有没有被订阅,都不会发送数据,直到ConnectableObservable实例的conntect方法被调用。

示例代码:
{% codeblock lang:js %}
const observable$ = new Observable(observable => {
console.log('Observable Start!');
observable.next();
}).publish();

console.log('start');
observable$.subscribe();

console.log('after Observable has been subscribed');
observable$.connect()

// 打印结果
// start
// after Observable has been subscribed
// Observable Start!
{% endcodeblock %}

observable被publish方法转化为Connectable模式,它在observable$.connect()方法调用后才发送数据,而不是subscribe后立即开始发送。

在异步处理中对比Promise

Promise是目前我们最常用的异步解决方案,它是一种对异步操作的封装,一个好吃的语法糖,它定义了三个状态,pedding、fulfilled和rejected。它和RxJS的不同之处:

  1. Promise从pedding状态变为其它状态时是不可撤销的,而RxJS可以取消订阅。
  2. Observable可以持续emit多个值,而Promise只能emit一个值。
  3. Observable提供了许多的工具函数。

示例代码:

Promise:
{% codeblock lang:js %}
const promise = new Promise((resolve, reject) => {
if (//success) {
resolve(res);
} else {
reject(err);
}
});
promise
.then()
.then()
.catch()
{% endcodeblock %}

Observable:
{% codeblock lang:js %}
const observable$ = new Observable(observer => {
let interval = setInterval(() => {
let count = 0;
observer.next(count)
}, 1000);
return () => {
clearInterval(interval);
}
});
observable$
.map(value => value.toString())
.subscribe(value => console.log(value));
{% endcodeblock %}
总结: RxJs是Promise进阶版,提供了更多的功能和更精细的控制。

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

推荐阅读更多精彩内容

  • 一.背景介绍 Rx(Reactive Extension -- 响应式扩展 http://reactivex.io...
    爱上Shu的小刺猬阅读 1,975评论 1 3
  • 介绍 RxJS是一个异步编程的库,同时它通过observable序列来实现基于事件的编程。它提供了一个核心的类型:...
    泓荥阅读 16,503评论 0 12
  • 本文章内部分图片资源来自RayWenderlich.com 本文结合自己的理解来总结介绍一下RxSwift最基本的...
    FKSky阅读 2,797评论 4 14
  • 标题 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 注:# 和一级标题之间建议保留一个字符的空格,这...
    demo11阅读 560评论 0 0
  • 【七月影语】20170808学习力践行Day79 依然在医院和家里奔跑,晚上在小姐姐家给孩子读了故事,背了古诗《题...
    暖小柒阅读 140评论 0 0