RxJs 仓库
本系列文章
你应该了解
的函数实现与组合应用- 初识RxJs与搭建仓库
- RxJs基础概念与使用
- 操作符篇
- 简易实现Observable
pull和push 是两种不同的协议,它们描述了数据生产者(Producer)如何数据消费者(Consumer)通信
pull
:在 pull 系统中Consumer
明确知道何时从Producer
中接收数据,但是Producer
不知道何时将数据发送给Consumer
。Producer | Consumer | |
---|---|---|
pull | 被动:在需要时产生数据。 | 主动:决定何时请求数据。 |
push | 主动:自己的节奏生成数据。 | 被动:对收到对数据做反应处理 |
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);
})
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));
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
Observable对象的函数 subscribe
中的方法就是观察者。
function observer(x){}
xxx.subscribe(observer);
订阅代表一次性资源的对象,通常是指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);
操作符是一个将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 就像一个可观察对象(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
调度程序控制何时开始订阅以及何时传递通知。它由三个部分组成
调度程序使您可以定义可观察对象将在哪些执行上下文中向其观察者传递通知
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
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)
实现逻辑和上面一样,只是不再挂载到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)