RxJS的常见用法

450 阅读3分钟

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

参考文章如下:

juejin.cn/post/711410…