RxJS(Reactive Extensions for JavaScript)是一个流行的 JavaScript 库,它实现了 ReactiveX 规范,提供了一组用于处理异步数据流的工具和函数。本文将介绍RxJS的常见用法。
- Observable 和 Promise转换
在 JavaScript 中,你可以使用 Observable 提供的 toPromise() 方法将 Observable 转换为 Promise。然而,在 RxJS 7 中,这个方法已经被废弃。 取而代之的是,RxJS 7 引入了两个新方法:firstValueFrom 和 lastValueFrom。这些方法分别返回一个 Promise,该 Promise 解析为 Observable 发出的第一个值和最后一个值。
//在RxJS中,我们可以使用toPromise()操作符将一个Observable转换为Promise。
const myObservable1 = from([1, 2, 3, 4]);
const myPromise1 = myObservable1.toPromise();
myPromise1.then((result) => console.log(result));//out is 4
//使用lastValueFrom将Observable转换为Promise
const lastFruit = await lastValueFrom(source$);
在RxJS中,将Promise转换为Observable可以通过使用from操作符来实现
const myPromise2 = new Promise((resolve) => {
setTimeout(() => resolve('Hello, World!'), 1000);
});
const myObservable2 = from(myPromise2);
myObservable2.subscribe((result) => console.log(result));
from操作符和of操作符区别
在RxJS中,创建一个发出数组元素的Observable非常简单。你可以使用from操作符来逐个发出数组中的每个元素,或者使用of操作符来作为单个发射发出整个数组。
const source1 = of(
[1, 2, 3]
);
const subscribe1 = source1.subscribe(val => console.log(val));
//输出是[1, 2, 3]
// 使用from操作符将数组转换为Observable
const source2 = from([1, 2, 3]);
// 订阅Observable以获取数组中的元素
source2.subscribe(val => console.log(val));
//输出是
// 1
// 2
// 3
- throwError操作符
RxJS 中的 throwError 是一个创建操作符,它创建一个 Observable,该 Observable 不返回任何项并立即发出错误通知。它可以用于与其他 observables 组合或捕获错误。它在 RxJS 6 中引入,取代了 Observable.throw。它接受一个错误对象作为参数。
- catchError操作符
const source2$ = throwError('这是一个错误!');
const example2$ = source2$.pipe(
catchError(error => {
console.error('捕获到错误:', error);
return of('我是错误处理后的结果');
})
);
example2$.subscribe({
next: value => console.log(`接收到值: ${value}`),
error: error => console.log(`接收到错误: ${error}`),
complete: () => console.log('完成'),
});
- forkJoin操作符
在 RxJS 中,forkJoin 是一个操作符,它接受一组 Observable,并返回一个新的 Observable。这个新的 Observable 会等待所有输入的 Observable 完成,然后发出一个数组,数组中的每个元素都是对应的输入 Observable 发出的最后一个值。
const { of, forkJoin } = require('rxjs')
const observable11 = of(1, 2, 3);
const observable21 = of('a', 'b', 'c');
// 使用 forkJoin 组合这两个 Observable
const combined$ = forkJoin([observable11, observable21]);
// 订阅组合后的 Observable
combined$.subscribe(([nums, chars]) => console.log(`数字: ${nums}, 字符: ${chars}`));
//输出: 数字: 3, 字符: c
- map, mergeMap, switchMap区别
使用 map 操作符
const source$ = of(1,2,3);
const result$ = source$.pipe(
map((value) => {
// 对于每个源值,返回一个新的 Observable
return of(value*3).pipe(delay(500));
})
);
result$.subscribe(data => data.subscribe(i => console.log(i)));
// output is
// 3
// 6
// 9
使用 mergeMap 操作符
const source$ = of(1,2,3);
const result1$ = source$.pipe(
mergeMap((value) => {
// 对于每个源值,返回一个新的 Observable
return of(value*3).pipe(delay(500));
})
);
result1$.subscribe(data => console.log(data));
// output is
// 3
// 6
// 9
switchMap 操作符
switchMap 是 RxJS 中的一个操作符,它的作用是当源 Observable 发射一个新的数据项时,取消订阅之前的数据流,并开始订阅新的数据流。这意味着只有最新的数据流会被发射出来,而之前的数据流会被丢弃
const source$ = of(1,2,3);
const result2$ = source$.pipe(
switchMap((value) => {
// 对于每个源值,返回一个新的 Observable
return of(value*3).pipe(delay(500));
})
);
result2$.subscribe(data => console.log(data));
// output is
// 9
若没有delay(500), map, mergeMap, switchMap的上面三个例子的结果如下:
// output is
// 3
// 6
// 9
const source$ = of(1,2,3);
const switched$ = source$.pipe(
map((value) => {
// 对于每个源值,返回一个新的 Observable
return of(value*3);
})
);
switched$.subscribe(data => data.subscribe(i => console.log(i)));
console.log('==========================================================')
const switched1$ = source$.pipe(
mergeMap((value) => {
// 对于每个源值,返回一个新的 Observable
return of(value*3);
})
);
switched1$.subscribe(data => console.log(data));
console.log('==========================================================')
const switched2$ = source$.pipe(
switchMap((value) => {
// 对于每个源值,返回一个新的 Observable
return of(value*3);
})
);
switched2$.subscribe(data => console.log(data));
在RxJS中,switchMap 是一个转换操作符,它对源 Observable 发出的每个值进行投影,将其映射到一个 Observable,并且只从最近投影的 Observable 中发出值。这个操作符通常用于那些需要取消前一个内部 Observable 并只关注最新的 Observable 的场景,比如自动完成搜索框。当源 Observable 发出一个新的值时,switchMap 会停止发出前一个内部 Observable 的值,并开始发出新的内部 Observable 的值。如果源 Observable 非常快速地连续发出多个值,switchMap 会取消前一个请求,这在需要确保每个请求都完成的场景(例如数据库写入操作)中可能不是最佳选择。在这种情况下,mergeMap 可能是更合适的操作符
- tap操作符
在 RxJS 中,tap 是一个操作符,它用于在不改变流的情况下访问 Observable 的值。tap 可以用于执行辅助作用(例如日志记录或调试),或者在不改变通知的情况下影响外部状态
// 创建一个 Observable
const source100$ = of(1, 2, 3);
// 使用 tap 操作符
const example100$ = source100$.pipe(
tap(val => console.log(`接收到值: ${val}`))
);
// 订阅新的 Observable
example100$.subscribe();
- takeUntil操作符
在RxJS中,takeUntil操作符的作用是让一个Observable发射值,直到另一个通知Observable发出一个值或者完成。简单来说,它可以让你在某个条件满足之前,持续接收Observable发出的值,一旦条件满足,就会停止接收并完成Observable序列。
例如,你可能有一个每秒发出值的Observable,你想在用户点击页面时停止发射值。你可以使用takeUntil操作符,以用户的点击事件作为通知Observable,来实现这个功能。
这里有一个基本的例子:
const source = interval(1000);
const clicks = fromEvent(document, 'click');
const result = source.pipe(takeUntil(clicks));
result.subscribe(x => console.log(x));
在这个例子中,source是每秒发出一个值的Observable,clicks是一个从文档中点击事件发出值的Observable。takeUntil(clicks)告诉source,一旦clicks发出一个值,就停止发射并完成。
- retry操作符
const { of,throwError,interval,retry,mergeMap } = require('rxjs')
const source = interval(1000);
const result = source.pipe(
mergeMap(val => val > 5 ? throwError(() => 'Error!') : of(val)),
retry(2) // 在错误发生时重试2次
);
result.subscribe({
next: value => console.log(value),
error: err => console.log(`${err}: Retried 2 times then quit!`)
});
//输出:
// 0
// 1
// 2
// 3
// 4
// 5
// 0
// 1
// 2
// 3
// 4
// 5
// 0
// 1
// 2
// 3
// 4
// 5
// Error!: Retried 2 times then quit!
- Subject 和 BehaviorSubject 区别
在 RxJS 中,Subject 和 BehaviorSubject 都是观察者模式的实现,它们都可以发出多个值并被多个观察者订阅 // Subject 是最基本的类型,它不会记住或重新发出旧值2。当一个新的观察者订阅 Subject 时,它只会从那一刻开始接收新发出的值。以下是一个使用 Subject 的例子:
const subject = new Subject();
subject.subscribe(value => console.log('Observer A:', value));
subject.next(1);
subject.next(2);
subject.subscribe(value => console.log('Observer B:', value));
subject.next(3);
// 在这个例子中,“Observer A” 会打印出 1, 2, 3,而 “Observer B” 只会打印出 3。
BehaviorSubject 是 Subject 的一种特殊类型,它需要一个初始值并且可以记住最新的值。当一个新的观察者订阅 BehaviorSubject 时,它会立即接收到最新的值。以下是一个使用 BehaviorSubject 的例子:
const subject = new BehaviorSubject(0); // 0 是初始值
subject.subscribe(value => console.log('Observer A:', value));
subject.next(1);
subject.next(2);
subject.subscribe(value => console.log('Observer B:', value));
subject.next(3);
// 在这个例子中,“Observer A” 会打印出 0, 1, 2, 3,而 “Observer B” 会打印出 2, 3。
//输出:
// Observer A: 0
// Observer A: 1
// Observer A: 2
// Observer B: 2
// Observer A: 3
// Observer B: 3
参考文章如下: