欢迎指错与讨论 : )

  当前RxJS版本:5.0.0-beta.10。更详细的内容尽在RxJS官网http://reactivex.io/rxjs/manual/overview.html。文章比较长,可以通过快捷键 command+f 或者 ctrl+f 搜索主要内容。  

   - 前言

     RxJS在ng2、redux-observable或者前端数据层中扮演一个重要角色,因此笔者想学好RxJS,提前做好准备。本文95%非原创,而是笔者对RxJS官网基础篇的翻译,如有错漏请指出。本文主要内容:简介和六大概念(Observable、Observer、Subscription、Subject、Operators、Scheduler)。

    具体Api请本博客的另外几篇中文api翻译文章:

    transform(转换)、filter (过滤)、combination/multicasting (组合、广播)、ErrorHanding/Condition/Mathematical(错误处理、情况处理、数学方法)

  - 安装

    import {Observable} from 'rxjs/Observable' // 1. 按需打包,减轻bundle.js大小

     import 'rxjs/add/observable/merge'; // 2. 按需导入函数,如merge

   - 一些概念

    - Observable( 可被观察的 ) : 是一个包含来自未来、可以被使用的值( value )或事件( event )的集合

    - Observe( 观察者 ):是一个知道如何监听、处理来自Obervable的值的函数集合

    - Subscription( 订阅 ):代表着Observable的执行动作,我们可以使用它来停止Obervable继续执行

    - Operators( 操作 ):一系列可以操作集合的pure function,像是过滤( filter )、转换( map )等等

    - Subject(  ):相当于一个事件发射器,是唯一能够向多个Observer广播值( value )的唯一手段

    - Schedulers( 调度 ):是一个中央调度员,帮助我们控制并发,协调计算( setTimeout、requestAnimationFrame等 )

  - Observable( 被观察者 )

    通常而言,Observable都会延迟产生值 ,比如当我们subscribe一个observable的时候它才会向我们发送这些值 let observable = Rx.Observable.range(1,3)

    - pull( 拉取 ) 每个函数都是一个数据的生产者,每个调用函数的那个'人',都会希望从这个函数中能够获得(pull) 唯一的返回值

    - push( 推送 ) 在数据生产者中( 如函数 ),会在特定时候把数据推送至消费者,消费者在获得数据之前啥也不会做

    - Observable与函数、promsise的对比:函数是当调用才同步计算,并最终只返回一个值的;promise是会或者不会返回一个值;Observable是当调用才同步或者异步地计算,并可能产生0到无穷多个值的。Observable就像一个没有参数的函数,并不断生成一些值供我们使用,因此它也像是一个事件发射机( EventEmitters )。在Observable中subscribe就像call一个函数,你订阅它,它才会被'启动'。同一个Observable对于不同的subscribe,是不会共享结果的( 通常情况下这样子的,但可以通过调用api来共享 )。

    - Observable四大核心:创建 、订阅 、 执行 、销毁 。

       订阅( subscribe )。当对一个Observable调用多个subscribe函数并创建多个observe时,observe之间不会共享任何东西,因为在Observable.create内部是对observe列表调用各自的回调的  Observable.create(function subscribe(observe){...})

       执行( Executing )。Next函数能够将数据传递给Observer,同时在执行期间,能在Observable内部调用多个Next( )函数。同时建议在Observabl内部使用try/catch语法。

       销毁Observe

  1. var observable = Rx.Observable.from([10, 20, 30]);
  2. var subscription = observable.subscribe(x => console.log(x));
  3. // Later:
  4. subscription.unsubscribe();

      销毁Observable

  1. var observable = Rx.Observable.create(function subscribe(observer) {
  2. var intervalID = setInterval(() => {
  3. ...
  4. }, 1000);
  5.  
  6. return function unsubscribe() {
  7. clearInterval(intervalID);
  8. };
  9. });

   - Observer( 观察者 )

    什么是观察者?观察者其实是数据的消费者,把来自Observble的数据拿过来使用。同时,Observer的本质是一系列的回调函数,是来自于Observable传递数据后的回调函数。我们可以直接通过subscribe函数创建观察者

  1. observable.subscribe(
  2. x => console.log('Observer got a next value: ' + x),
  3. err => console.error('Observer got an error: ' + err),
  4. () => console.log('Observer got a complete notification')
  5. );

  - Subscription( 订阅 )

    什么是Subscription?它其实是代表着Observable的'执行'的对象,我们可以通过它的 unsubscribe 方法销毁Observable的执行。同时我们能使用 add 方法,一次销毁多个

  1. var subscription = observable1.subscribe(x => console.log('first: ' + x));
  2. var childSubscription = observable2.subscribe(x => console.log('second: ' + x));
  3.  
  4. subscription.add(childSubscription);
  5.  
  6. setTimeout(() => {
  7. subscription.unsubscribe();
  8. }, 1000);

  - Subject(  )

    什么是Subject?它是在Rx中一种比较特殊的Observable( 同时它也是Observer ),它能够让值( value )同时向多个Observer传播( 广播 )。而一般的Observable都是' 单播 '形式,即:每一个订阅了同一个Observable的observer,实际上是拥有不同的、独立的Observable的执行( 原文:each subscribed Observer owns an independent execution of the Observable ),而Subject是多播的。

  1. // Observable对比Subject
  2. let source = Rx.Observable.create((observer)=>{
  3. observer.next('1');
  4. observer.next('2');
  5. });
  6. source.subscribe((x)=>{console.log(x);});
  7. source.subscribe((x)=>{console.log(x);});
  8. // 输出 1 2 1 2
  9. let subject = new Rx.Subject();
  10. subject.subscribe((x)=>{console.log(`${x}`);});
  11. subject.subscribe((x)=>{console.log(`${x}`);});
  12. subject.next(1);
  13. subject.next(2);
  14. // 输出 1 1 2 2     
  1. // Subject可以在'多播'情景下对Observable进行优化
  2. // 明显看到在subject下,Observable只执行了一次
  3. var source = Rx.Observable.create((observer)=>{
  4. console.log(`source was called`);
  5. observer.next(1);observer.next(2);observer.next(3);
  6. });
  7. source.subscribe({next: (v) => console.log('observerA: ' + v)});
  8. source.subscribe({next: (v) => console.log('observerB: ' + v)});
  9. // 输出为 'source was called' observerA: 1 observerA: 2
  10. // 'source was called' observerB: 1 observerB: 2
  11.  
  12. var source = Rx.Observable.create((o)=>{
  13. console.log(`source was called`);
  14. o.next(1);o.next(2);
  15. });
  16. var subject = new Rx.Subject();
  17. var multicasted = source.multicast(subject);
  18.  
  19. // 原理是`subject.subscribe({...})`:返回的multicasted是一个connectableObservable
  20. multicasted.subscribe({next: (v) => console.log('observerA: ' + v)});
  21. multicasted.subscribe({next: (v) => console.log('observerB: ' + v)});
  22.  
  23. // 原理是 `source.subscribe(subject)`:
  24. multicasted.connect();
  25. // 输出 ‘source was called’ observerA: 1 observerB: 1
  26. // observerA: 2 observerB: 2

    可以单个取消订阅状态 observer.subscribe( ) ,也可以直接销毁Subject subscriptionConnect.unsubscribe( )

    - refCount( ) 该api能监听当前connectableObservable的'连接状态',当有大于0个subscribe挂在它上面它会自动执行 connect ,无subscribtion的时候会自动执行 unsubscribe( )

  1. var refCounted = source.multicast(subject).refCount();

    - BehaviorSubject() 它能储存上一次从Observable发过来的值,每当有新的observer的时,会把改值立即发送给它

  1. var subject = new Rx.BehaviorSubject(0)// 初始值

    - ReplaySubject( 重现 ) 是BehaviorSubject的加强版,它能储存从Observable发送过来的一系列值,当有新的observer连接时,会把这些值发送给它。

  1. var subject = new Rx.ReplaySubject(3); // 缓存空间为3

       - AsyncSubject(异步)仅将从Observable发送过来的最后一个值发送给Observe

  1. var subject = new Rx.AsyncSubject();

  - Operators

    什么是Operators?Operators是Rx中最有用的一系列函数,它们建立在Observable之上,并能优雅地以同步代码的写法,将不同的异步流代码链式组合到一起。同时,Operator都是pure的,因为这些函数不会直接修改传入进来的Observable,而是经过修饰之后返回一个新Observable。

    在链式操作中,下一个operator会根据上一个operator修改后的Observable继续工作。

    - 具体请本博客的另外几篇中文api翻译文章:

    transform(请点击)、filter (请点击)、combination/multicasting (请点击)、ErrorHanding/Condition/Mathematical(请点击)

  - Scheduler

    Scheduler有咩用?Scheduler能控制一个订阅的开始、数据的传递。它由三部分组成:

     - scheduler是一种数据结构,它知道如何基于优先级或者其他标准对任务队列进行储存

     - scheduler是一个执行环境,它指何时何地地执行任务

     - scheduler有一个' 时钟 '的概念,它能让我们自己定义,当Observable向Observer时会处于什么环境下( context )

  1. // observeOn( RX.Scheduler.async )
  2. var observable = Rx.Observable.create(function (observer) {
  3. observer.next(1);observer.next(2);
  4. })
  5. .observeOn(Rx.Scheduler.async);
  6.  
  7. console.log('just before subscribe');
  8. observable.subscribe({next: x => console.log('got value ' + x)});
  9. console.log('just after subscribe');
  10. // 输出
  11. // just before subscribe just after subscribe
  12. // got value 1 got value 2

      - Scheduler类型

        - Scheduler.queue 基于当前的事件框架在一个队列上工作,当我们需要遍历操作时可以使用它

        - Scheduler.asap

        - Scheduler.async 在内部,Schedules会使用setInterval,当我们需要以时间为基线时就使用它

   - 基础

    - 创建流: Observable.create、of、from、fromEvent( target,eventType )、fromPromise、bindCallback( 把callback写法转换为链式写法 )     

  1. let exists = Rx.Observable.bindCallback(fs.exists);
  2. exists('file.txt').subscribe( exist=>console.log(`exist? : ${exist} `) )

    - 事件流: filter、delay( 延时 )、throttleTime( 时间间隔 )、debounceTime( 事件暂停x毫秒后 )、take( 执行x次后停止 )、takeUtil( 取消订阅 )

  1. let inputStream = Rx.Observable.fromEvent(document.querySelector('input'), 'keyup')
  2. let stopStream = Rx.Observable.fromEvent(document.querySelector('button'), 'click')
  3. inputStream.throttleTime(200) // 每隔200毫秒才释放一次
  4. .takeUtil(stopStream) // 当触发时,停止订阅
  5. .subscribe(($event)=> {console.log(`${$event.target.value}`)}) // 事件对象

    - 转换流、过滤流:map、distinct( 过滤重复 )、distince( 过滤连续重复 )

  1. // 输入hello world
  2. input.pluck('target', 'value').distinctUntilChanged()
  3. .subscribe(value => console.log(value)); // "helo wrd"
  4. input.pluck('target', 'value').distinct()
  5. .subscribe(value => console.log(value)); // "helo world"

  - 创建一个应用

    - RxJS的工具函数都是pure、无状态的一类函数。但我们的应用中往往需要记录大量的state,那在Rx如何记录状态呢?类似于redux,rx中的scan函数能够使用reduce函数,将流的结果合并。我们需要做的仅仅是保存这个状态( state )值

  1. // 基础模式
  2. var button = document.querySelector('button');
  3. Rx.Observable.fromEvent(button, 'click')
  4. // 内部的reduce函数能够积累(此处是相加,若是对象可以是Object.assign),并相应变化
  5. .scan(count => count + 1, 0)
  6. // Set the count on an element each time it changes
  7. .subscribe(count => document.querySelector('#count').innerHTML = count);

    - 一个更好的模式

  1. var button = document.querySelector('button');
  2. Rx.Observable.fromEvent(button, 'click')
  3. // 返回了一个, 类似redux中 经过switch(action.type)的reducer 与函数
  4. .map(() => state => Object.assign({}, state, {count: state.count + 1}))
  5. // 直接把函数作用于初始化state,scan同时能保存这个更新后的state
  6. .scan((state, changeFn) => changeFn(state), {count: 0})
  7. .subscribe(state => document.querySelector('#count').innerHTML = state.count);

     - 对于某一个组件还可以

  1. var state = Rx.Observable.merge(
  2. increase,
  3. decrease,
  4. input
  5. ).scan((state, changeFn) => changeFn(state), {
  6. count: 0,
  7. inputValue: ''
  8. });

       

    

    

    

    

          

    

  

      

[译]RxJS 5.X基础篇的更多相关文章

  1. Python 经典面试题汇总之基础篇

    基础篇 1:为什么学习Python 公司建议使用Python,然后自己通过百度和向有学过Python的同学了解了Python.Python这门语言,入门比较简单,它简单易学,生态圈比较强大,涉及的地方 ...

  2. Qt入门之基础篇 ( 一 ) :Qt4及Qt5的下载与安装

    转载请注明出处:CN_Simo. 导语: Qt是一个跨平台的C++图形界面应用程序框架.它提供给开发者建立图形用户界面所需的功能,广泛用于开发GUI程序,也可用于开发非GUI程序.Qt很容易扩展,并且 ...

  3. python面试题库——1Python基础篇

    第一部分 Python基础篇(80题) 为什么学习Python? 语言本身简洁,优美,功能超级强大,跨平台,从桌面应用,web开发,自动化测试运维,爬虫,人工智能,大数据处理都能做 Python和Ja ...

  4. python基础篇(六)

    PYTHON基础篇(六) 正则模块re A:正则表达式和re模块案例 B:re模块的内置方法 时间模块time A:时间模块的三种表示方式 B:时间模块的相互转换 随机数模块random A:随机数模 ...

  5. 好未来数据中台 Node.js BFF实践(一):基础篇

    好未来数据中台 Node.js BFF实践系列文章列表: 基础篇 实战篇(TODO) 进阶篇(TODO) 好未来数据中台的Node.js中间层从7月份开始讨论可行性,截止到9月已经支持了4个平台,其中 ...

  6. C#多线程之基础篇3

    在上一篇C#多线程之基础篇2中,我们主要讲述了确定线程的状态.线程优先级.前台线程和后台线程以及向线程传递参数的知识,在这一篇中我们将讲述如何使用C#的lock关键字锁定线程.使用Monitor锁定线 ...

  7. 一步步学习javascript基础篇(0):开篇索引

    索引: 一步步学习javascript基础篇(1):基本概念 一步步学习javascript基础篇(2):作用域和作用域链 一步步学习javascript基础篇(3):Object.Function等 ...

  8. 2000条你应知的WPF小姿势 基础篇<15-21>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师,对C#和WPF有着极深的热情.最为出色的是他维护了两个博客:2,000Things You Should Know ...

  9. ABP框架实践基础篇之开发UI层

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 说明 其实最开始写的,就是这个ABP框架实践基础篇.在写这篇博客之前,又回头复习了一下ABP框架的理论,如果你还没学习,请查看AB ...

随机推荐

  1. javascript权威指南笔记

    最近每天工作之余看下js的细节部分,时间不是很多,所以看的进度也不会太快,写个博客监督自己每天都看下. 以前不知道的细节或者以前知道但是没注意过的地方都会记录下来,所以适合有一定基础的,不适合零基础新 ...

  2. .net请求URL过长,解决方案

    <system.web> 节点下加上 <httpRuntime requestValidationMode="2.0" maxQueryStringLength= ...

  3. ASP.NET MVC5中的Model验证

    Model验证是ASP.NET MVC中的重要部分,它主要用于判断输入的数据类型及值是否符合我们设定的规则,这篇文章就介绍下ASP.NET MVC中Model验证的几种方式. 后台验证 DataAnn ...

  4. asp.net core 简单部署

    目的 练习asp.net core的技术使用.部署等.目前拥有一台阿里云服务器(超级低配版本),安装了centos系统,打算将练习项目发布到该环境中.可能需要做以下准备工作. 以前没接触过linux正 ...

  5. 【无私分享:ASP.NET CORE 项目实战(第八章)】读取配置文件(二) 读取自定义配置文件

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 我们在 读取配置文件(一) appsettings.json 中介绍了,如何读取appsettings.json. 但随之产生 ...

  6. php简单实现socket通信

    socket通信的原理在这里就不说了,它的用途还是比较广泛的,我们可以使用socket来做一个API接口出来,也可以使用socket来实现两个程序之间的通信,我们来研究一下在php里面如何实现sock ...

  7. jq实现发送短信验证码

    前端的工作经常会涉及到短信验证的功能(注册或获取当前手机号信息),于是自己也写了一个,路过的小伙伴可以看一下 未点击状态 点击之后的状态 var timer=""; ; var v ...

  8. 二胎上位之路:html5报表和原生报表的笑尿撕逼

    前段时间,小编和我们移动端产品经理之间发生了一场罕见的撕逼大战. (看到撕逼二字,估计读者朋友们来劲了,呵呵呵……) 事情起因是这样的.小编基于对客户需求以及同行产品的了解,发了一篇关于报表在各种屏幕 ...

  9. 在Ubuntu和Linux Mint上安装Oracle JDK

    在Ubuntu和Linux Mint上安装Oracle JDK 使用下面的命令安装,只需一些时间,它就会下载许多的文件,所及你要确保你的网络环境良好: sudo add-apt-repository ...

  10. Dagger2 (三) 总结篇

    一.Dagger2注入原理 Dagger2以自动生成代码的形式,帮助我们构建依赖图,在使用依赖的时候方便清晰,这里说明一点,在我们使用Dagger2的时候,绝大多数错误都是编译器就会暴漏出来,这也就决 ...