RxJS 是一个用于处理异步和事件流的库,提供了许多强大的操作符来处理 Observables,使得用户对于数据流的处理更加的高效。我们可以通过操作符轻松组合和变换多个数据流,同时它支持多种数据源的处理,包括事件、HTTP 请求、WebSocket 等。操作符在对于RXJS的应用中是不可或缺的一环。
前文:浅析RXJS
基本操作符
- 创建操作符
-
of():创建一个 Observable,发出指定的值。
-
from():从一个数组、Promise 或其他可迭代对象创建 Observable。
import { from } from 'rxjs';
import { of, from, interval } from 'rxjs';
// 使用 of 创建一个 Observable
// of 用于从一组值创建一个 Observable。它可以接受任意数量的参数,并将这些参数作为单独的值发出。
const observableOf = of(1, 2, 3);
// 使用 from 创建一个 Observable
// from 用于将其他类型的对象(如数组、Promise、Iterable、Observable 等)转换为 Observable。
// 使用 from 来处理异步数据源或将集合转换为 Observable,适合于需要逐个发出值的场景。
const observableFrom = from([1, 2, 3]);
- 变换操作符
-
map():对 Observable 发出的每个值应用一个函数,并返回一个新的 Observable。
-
filter():过滤 Observable 发出的值,仅保留满足条件的值。
-
mergeMap()(也称为flatMap()):将每个发出的值映射为一个 Observable,并将这些 Observables 合并为一个
import { map } from 'rxjs/operators';
const doubled$ = source$.pipe(map(x => x * 2));
import { filter } from 'rxjs/operators';
const even$ = source$.pipe(filter(x => x % 2 === 0));
import { mergeMap } from 'rxjs/operators';
const source$ = of(1, 2, 3);
const combined$ = source$.pipe(mergeMap(x => of(x, x + 1)));
// 订阅 combined$,以查看输出
combined$.subscribe(value => console.log(value));
// 当 x 为 1 时,of(1, 2) 会被创建;
// 当 x 为 2 时,of(2, 3) 会被创建;
// 当 x 为 3 时,of(3, 4) 会被创建。
// mergeMap() 会将这些新的 Observables 合并成一个单一的 Observable。
// 最终的输出顺序依次是 1, 2, 2, 3, 3, 4。
- 组合操作符
-
combineLatest():将多个 Observables 的最新值组合成一个数组。
-
forkJoin():等待所有 Observables 完成,并发出它们的最后一个值。
import { combineLatest } from 'rxjs';
// 当 obs1$ 或 obs2$ 中的任意一个发出新值时,combined$ 会发出一个包含这两个最新值的数组。
const combined$ = combineLatest([obs1$, obs2$]);
import { forkJoin } from 'rxjs';
// 如果有任何一个 Observable 没有完成,forkJoin() 将不会发出任何值。
const finalValues$ = forkJoin([obs1$, obs2$]);
- 处理异步操作
-
debounceTime():在发出值前,等待指定的时间,避免快速连续的触发。
-
switchMap():用于处理高频率的事件流,只保留最后一个发出的 Observable。
import { debounceTime } from 'rxjs/operators';
// 可以实现防抖
const debounced$ = source$.pipe(debounceTime(300));
import { switchMap } from 'rxjs/operators';
// 使用 throttleTime 实现节流
// 将每个发出的值映射为一个新的 Observable,并且只保留最后一个发出的 Observable 的结果。
// 它会在新的值发出时取消之前的 Observable,适用于处理高频率的事件流。
const throttled$ = source$.pipe(
throttleTime(300), // 每 300 毫秒只允许一次事件触发
switchMap(value => fetchData(value)) // 处理高频率的事件流
);
- 错误处理操作符
-
catchError():捕获 Observable 中的错误,并返回一个新的 Observable。
import { catchError } from 'rxjs/operators';
const safe$ = source$.pipe(catchError(err => of('Error occurred')));
- 结束操作符
-
take():只发出前 n 个值,然后完成。
-
takeUntil():直到另一个 Observable 发出值时完成。
import { take } from 'rxjs/operators';
const firstThree$ = source$.pipe(take(3));
import { takeUntil } from 'rxjs/operators';
const until$ = source$.pipe(takeUntil(stop$));
- pipe (...)
用于将多个操作符组合在一起,以便对 Observable 的数据流进行灵活地处理。
操作符的顺序非常重要,后面的操作符会基于前面的输出进行处理。 pipe() 方法返回一个新的 Observable,原始 Observable 不会被修改。
import {of} form 'rxjs';
import {map,filter} from 'rxjs/operators';
const source$=of(1,2,3,4,5);
const result$=source$.pipe(
filter(value=>value%2===0),//过滤出偶数
map(value=>value*10) //将每个偶数乘以10
);
// 订阅
result$.subscribe(result=>{
console.log(result);
})
高级操作符
- 更多高级操作符,如 concatMap、exhaustMap、distinctUntilChanged 等。
-
concatMap():适用于需要按顺序处理每个值的场景。import { from } from 'rxjs'; import { concatMap, delay } from 'rxjs/operators'; const source$ = from([1, 2, 3]); // concatMap() 将每个发出的值映射为一个新的 Observable,并按顺序处理这些 Observables。 // 它会等待前一个 Observable 完成后,再处理下一个。 const result$ = source$.pipe( concatMap(value => of(`Processed ${value}`).pipe(delay(1000))) // 每个值延迟 1 秒处理 ); result$.subscribe(result => console.log(result)); -
exhaustMap():exhaustMap()会将每个发出的值映射为一个新的 Observable,但如果前一个 Observable 还在处理,则会忽略后续的值,直到前一个完成。 -
distinctUntilChanged():适用于去重场景,只发出与前一个值不同的值。
- 组合多个 Observables:使用 zip、forkJoin、concat 等方法组合多个 Observables。 这些组合操作符提供了不同的方式来处理多个 Observables:
zip():适用于按顺序组合多个 Observables 的值,只有当所有输入 Observables 都发出新值时,才会发出组合的值。forkJoin():适用于等待所有 Observables 完成后一次性获取它们的最后值。concat():适用于按顺序处理多个 Observables,每个只有在前一个完成后才能开始。
通过灵活使用这些组合操作符,可以有效地管理复杂的异步数据流。
- 错误处理:使用 catchError、retry、retryWhen 等操作符处理错误。
-
catchError():用于捕获 Observable 中的错误并返回一个新的 Observable,适用于处理错误并提供备选值的场景。import { of, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; const source$ = throwError('Something went wrong!').pipe( catchError(err => { console.error('Caught error:', err); return of('Error handled, returning fallback value.'); }) ); source$.subscribe( value => console.log('Value:', value), error => console.log('Error:', error) ); -
retry():用于在发生错误时重新订阅 Observable,可以指定重试的次数。import { of, throwError } from 'rxjs'; import { retry, map } from 'rxjs/operators'; let attempt = 0; const source$ = of('Hello').pipe( map(value => { if (attempt < 2) { attempt++; throw new Error('Simulated error'); } return value; }), // 用于在 Observable 发生错误时重新订阅它。这里的参数 2 表示最多重试 2 次。 retry(2) // 尝试重试 2 次 ); source$.subscribe( value => console.log('Value:', value), error => console.log('Error:', error.message) ); -
retryWhen():提供更灵活的重试机制,当 Observable 发生错误时,可以基于这个条件来决定是否重试。你可以通过返回一个新的 Observable 来控制重试的逻辑。返回一个
timerObservable 是一种常见的做法,通常用于在重试之间引入延迟。可以返回其他类型的 Observable,这样可以实现更灵活的重试逻辑。
例如:
-
of():立即发出一个值,然后重试。
-
interval():发出值的间隔 Observable,用于定期重试
-
throw error:在重试次数达到上限时,抛出错误是一个常见的做法。这会导致整个 Observable 进入错误状态,并且会被后续的
catchError()捕获。
import { of, throwError, timer } from 'rxjs'; import { retryWhen, mergeMap, catchError } from 'rxjs/operators'; let attempt = 0; const source$ = of('Hello').pipe( // 用于将每个发出的值映射为一个新的 Observable。 mergeMap(value => { if (attempt < 2) { attempt++; return throwError('Simulated error'); } return of(value); }), // 当 Observable 发生错误时,使用这个操作符定义重试逻辑。 // 通常返回的是一个控制重试逻辑的 Observable retryWhen(errors => // 发出错误的 Observable。 errors.pipe( // 使用 mergeMap,处理每个错误和重试的逻辑。 mergeMap((error, index) => { console.log(`Attempt ${index + 1}: ${error}`); // 如果重试次数小于 2,则使用 timer(1000) 创建一个 Observable,在 1 秒后发出值,表示等待 1 秒后重试。 if (index < 2) { // 返回一个 timer Observable,用于在重试之间引入延迟。 return timer(1000); // 等待 1 秒后重试 } throw error; // 超过重试次数,抛出错误 }) ) ), catchError(err => of(`Error handled: ${err}`)) ); source$.subscribe(value => { console.log('Value:', value); }); -