[RxJS学习之旅] 之宏观了解基本概念与使用

RxJs 仓库

本系列文章

  1. 你应该了解的函数实现与组合应用
  2. 初识RxJs与搭建仓库
  3. RxJs基础概念与使用
  4. 操作符篇
  5. 简易实现Observable

文章目录

  • 基本概念
    • 被观察对象(Observable)
      • pull与push
        • 特性
        • 核心概念
    • 观察者(Observer)
    • Subscription
    • 操作符(Operators)
    • Subject
    • Schedulers
    • map 实现与分析
      • 原型上添加
      • 通过 pipe 组合

基本概念

被观察对象(Observable)

pull与push

pull和push 是两种不同的协议,它们描述了数据生产者(Producer)如何数据消费者(Consumer)通信

  • pull:在 pull 系统中Consumer明确知道何时从Producer中接收数据,但是Producer不知道何时将数据发送给Consumer
    每个JavaScript函数都是一个Pull系统。该函数是数据的生产者,并且调用该函数的代码通过从调用中“拉出” 单个返回值来使用它。
Producer Consumer
pull 被动:在需要时产生数据。 主动:决定何时请求数据。
push 主动:自己的节奏生成数据。 被动:对收到对数据做反应处理
  • push:在推送系统中,生产者确定何时将数据发送给消费者。消费者不知道何时接收该数据
    Promise 是当今JavaScript中最常见的Push系统类型。

RxJs 引入Observables这是一个用于JavaScript的新Push系统,一个Observable是多个值的生产者,将它们“推送”到观察者(消费者)。


⬆ back to top

特性

  • 可观察值就像带有零参数的函数,但是将其概括化以允许多个值。
function foo() {
  console.log('Hello');
  return 42;
}

const x = foo.call(); // same as foo()
console.log(x);
const y = foo.call(); // same as foo()
console.log(y);

//print

"Hello"
42
"Hello"
42

使用Observables编写上面的代码

const foo=new Observable(subscriber=>{
    console.log('Hello')
    subscriber.next(42);
})

foo.subscribe(x=>{
    console.log(x);
})
foo.subscribe(y=>{
    console.log(y);
})
  • 订阅一个Observable类似普通函数调用一样。
console.log('before');
console.log(foo.call());
console.log('after');

这与Observables相同:

console.log('before');
foo.subscribe(x=>{
    console.log(x);
})
console.log('after');
  • 可观察对象能够同步或异步传递值。
    一个可观察对象可以随着时间的推移“返回”多个值,但是函数返回值只有一个
function foo() {
  console.log('Hello');
  return 42;
  return 100; // 永远不会发生
}
import { Observable } from 'rxjs';
 
const foo = new Observable(subscriber => {
  console.log('Hello');
  subscriber.next(42);
  subscriber.next(100); // "return" another value
  subscriber.next(200); // "return" yet another
  setTimeout(() => {
    subscriber.next(300); // happens asynchronously
  }, 1000);
});
 
console.log('before');
foo.subscribe(x => {
  console.log(x);
});
console.log('after');

//print
before
Hello
42
100
200
after
300
  • func.call()意思是 同步给我一个值
  • observable.subscribe()表示 给我同步或异步提供任意数量的值

⬆ back to top

核心概念

  • 创建可观察物
import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
  const id = setInterval(() => {
    subscriber.next('hi')
  }, 1000);
});

  • 订阅可观察物

订阅Observable就像调用一个函数,提供将数据传递到的回调。

observable.subscribe(x => console.log(x));
  • 执行可观察的
    可观察的执行可以提供三种类型的值:
  1. next:发送一个值,例如数字,字符串,对象等。
  2. error:发送JavaScript错误或异常。
  3. complete:不发送值。
import { Observable } from 'rxjs';
 
const observable = new Observable(function subscribe(subscriber) {
  try {
    subscriber.next(1);
    subscriber.next(2);
    subscriber.next(3);
    subscriber.complete();
  } catch (err) {
    subscriber.error(err); // delivers an error if it caught one
  }
});
  • 处置可观察物

订阅后,您将获得一个Subscription,代表正在进行的执行。只需调用unsubscribe()即可取消执行。

import { from } from 'rxjs';

const observable = from([10, 20, 30]);
const subscription = observable.subscribe(x => console.log(x));
// Later:
subscription.unsubscribe();

例如,这是我们通过以下方式清除间隔执行集的方式setInterval:

const observable = new Observable(function subscribe(subscriber) {
  // Keep track of the interval resource
  const intervalId = setInterval(() => {
    subscriber.next('hi');
  }, 1000);

  // Provide a way of canceling and disposing the interval resource
  return function unsubscribe() {
    clearInterval(intervalId);
  };
});

去除Observable,下面同样可以实现同等功能,只是存在得安全性和组合性差。

interface Sub{
  next:(v:any)=>void
}
function subscribe(subscriber:Sub){
  const intervalId=setInterval(()=>{
    subscriber.next('h1')
  },1000)
  return function unsubscribe(){
    clearInterval(intervalId)
  }
}
const unsubscribe =subscribe({next:(x)=>{console.log(x)}});

//later
unsubscribe();

⬆ back to top

观察者(Observer)

Observable对象的函数 subscribe中的方法就是观察者。

function observer(x){}
xxx.subscribe(observer);

Subscription

订阅代表一次性资源的对象,通常是指Observable执行。它还有一个方法 unsubscribe它不带任何参数,而只是释放该订阅所拥有的资源。

import { interval } from 'rxjs';
 
const observable1 = interval(400);
const observable2 = interval(300);
 
const subscription = observable1.subscribe(x => console.log('first: ' + x));
const childSubscription = observable2.subscribe(x => console.log('second: ' + x));
 
subscription.add(childSubscription);
 
setTimeout(() => {
  // Unsubscribes BOTH subscription and childSubscription
  subscription.unsubscribe();
}, 1000);

操作符(Operators)

操作符是一个将Observable作为其输入并返回另一个Observable的函数。这是一个纯函数操作:使Observable保持不变

操作符就是在 subscribe接上一个Observer之前的一系列数据处理。并且每一个操作都是返回一个全新的Observable对象的函数。

import {Observable} from  'rxjs'
import {map} from 'rxjs/operators'

const onSubscribe=observer=>{
    observer.next(1);
    observer.next(2)
};
const source$=new Observable<number>(onSubscribe);
source$.pipe(map(x=>x*2)).subscribe(console.log)

分类

  • 创建类
  • 转换类
  • 过滤类
  • 合并类
  • 多播类
  • 错误处理类
  • 条件分支类
  • 数字和合计类

上手实例:

import {from} from 'rxjs'
import {map,filter} from 'rxjs/operators'

import {addItem} from './utils'

let numersObservable=from([1,2,3,4,5]);
let squaredNumbers=numersObservable.pipe(
    filter(val=>val>2),
    map(val=>val*val)
);

let subscription=squaredNumbers.subscribe(result=>{
    addItem(result)
})
subscription.unsubscribe();
 

关于更多操作细节和使用请这里

更多操作符使用

⬆ back to top

Subject

Subject 就像一个可观察对象(Observable),但它传播给多个观察者。

import {Subject} from 'rxjs'

const subject=new Subject<number>();

subject.subscribe({next:(x)=>{console.log('观察这A',x)}})

subject.subscribe({next:(x)=>{console.log('观察者B',x)}})

subject.next(1);
subject.next(2);
 
// Logs:
//观察这A 1
//观察者B 1
//观察这A 2
//观察者B 2

Schedulers

调度程序控制何时开始订阅以及何时传递通知。它由三个部分组成

  • 调度程序是一种数据结构。
  • 调度程序是一个执行上下文。
  • 调度程序具有(虚拟)时钟

调度程序使您可以定义可观察对象将在哪些执行上下文中向其观察者传递通知

import { Observable, asyncScheduler } from 'rxjs';
import { observeOn } from 'rxjs/operators';
 
const observable = new Observable((observer) => {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.complete();
}).pipe(
  observeOn(asyncScheduler)
);
 
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');

⬆ back to top

map 实现与分析

原型上添加

operator/map.ts

import {Observable} from 'rxjs'
/**
 * 1. 返回一个全新的Observable对象
 * 2. 对上游和下游的订阅及退订处理
 * 3. 处理异常情况
 * 4. 及时释放资源
 */
function map(project){
    return new Observable(observer=>{
        const sub=this.subscribe({
            next:value=>{
                try {
                    observer.next(project(value))
                } catch (error) {
                    observer.error(error)
                }
            },
            error:err=>observer.error(err),
            complete:()=>observer.complete()
        });
        return{
            unsubscribe:()=>{
                sub.unsubscribe()
            }
        }
    });
}
Observable.prototype.map=map;

测试

import {Observable} from  'rxjs'
require('./operator/map')
const onSubscribe=observer=>{
    observer.next(1);
    observer.next(2)
};
const source$=new Observable<number>(onSubscribe);
source$.map(x=>x*3).subscribe(console.log)

通过 pipe 组合

实现逻辑和上面一样,只是不再挂载到Observer中并使用es6简写


/**
 * 方式二,通过pipe 形式引入
 */
export const map=fn=>ob$=>new Observable(observer=>{
    const sub=ob$.subscribe({
        next:value=>{
            try {
                observer.next(fn(value))
            } catch (error) {
                observer.error(error)
            }
        },
        error:err=>observer.error(err),
        complete:()=>observer.complete()
    });
    return{
        unsubscribe:()=>{
            sub.unsubscribe()
        }
    }
})

测试

import {Observable} from  'rxjs'
import {map} from  './operator/map'

const onSubscribe=observer=>{
    observer.next(1);
    observer.next(2)
};
const source$=new Observable<number>(onSubscribe);
source$.pipe(map(x=>x*2)).subscribe(console.log)

你可能感兴趣的:(#,Rx.js)