上一篇介绍了基本概念,这篇介绍一下实际应用中经常使用的一些操作符。
错误处理和重试
重试机制:使用retry
和retryWhen
来重试失败的操作。对于接口不稳定时候提高用户体验异常有效。
import { ajax } from 'rxjs/ajax';
import { retryWhen, delay, take } from 'rxjs/operators';
ajax.getJSON('https://www.summer889.com/data').pipe(
// 重试三次,每次延迟1秒
retryWhen(errors => errors.pipe(delay(1000), take(3)))
).subscribe(
data => console.log(data),
err => console.error('Failed after 3 retries', err)
);
调试
tap
操作符用于在不改变数据流的情况下插入调试代码:
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
of(1, 2, 3).pipe(
tap(value => console.log(`Value before transformation: ${value}`)),
map(value => value * 10)
).subscribe(console.log);
自定义操作符
创建自定义操作符,以便在多个地方重用逻辑:
import { Observable } from 'rxjs';
function customOperator() {
return (source) => new Observable(observer => {
return source.subscribe({
next(value) {
// 在这里处理值
observer.next(value * 2);
},
error(err) { observer.error(err); },
complete() { observer.complete(); }
});
});
}
// 自定义操作符
const source = of(1, 2, 3);
source.pipe(customOperator()).subscribe(console.log); // 输出: 2, 4, 6
表单处理
使用RxJs
处理表单输入和验证:
import { fromEvent, merge } from 'rxjs';
import { map, startWith, debounceTime } from 'rxjs/operators';
const username = document.getElementById('username');
const tip = document.getElementById('tip');
const nameChanges$ = fromEvent(username, 'input').pipe(
map(event => event.target.value),
debounceTime(300),
startWith('') // 初始值为空
);
nameChanges$.subscribe(value => {
tip.textContent = value.length < 3 ? '输入不能小于3个' : '';
});
调试工具
RxJS
提供了rxjs-spy
工具来帮助调试:
npm install rxjs-spy --save-dev
// so easy
import { install } from 'rxjs-spy';
install()
高级操作符
这几个没用过,学习一下希望以后用得上:
- combineLatest: 用于组合多个可观察对象,只有在其中至少一个可观察对象发出数据后,才会发出最新的值。
import { combineLatest, of } from 'rxjs';
import { map } from 'rxjs/operators';
const obs1 = of(1, 2, 3);
const obs2 = of('A', 'B', 'C');
combineLatest([obs1, obs2]).pipe(
map(([num, char]) => `${num}-${char}`)
).subscribe(console.log);
// 输出: "3-C"(最后一个发出的值)
- merge: 合并多个可观察对象,使它们的发出时间重叠。
import { merge, interval } from 'rxjs';
import { take } from 'rxjs/operators';
const obs1 = interval(1000).pipe(take(3)); // 每秒发出0, 1, 2
const obs2 = interval(500).pipe(take(6)); // 每半秒发出0, 1, 2, 3, 4, 5
merge(obs1, obs2).subscribe(console.log);
// 可能的输出: 0, 0, 1, 1, 2, 2, 3, ...
- switchMap: 用于将一个可观察对象映射到另一个可观察对象,并取消之前的可观察对象的订阅。
import { fromEvent } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';
import { ajax } from 'rxjs/ajax';
const searchBox = document.getElementById('searchBox');
fromEvent(searchBox, 'input').pipe(
map(event => event.target.value),
switchMap(searchTerm => ajax.getJSON(`https://www.summer889.com/search?q=${searchTerm}`))
).subscribe(data => console.log(data));
- concatMap: 用于串行处理多个内部可观察对象。
import { of, interval } from 'rxjs';
import { concatMap, take } from 'rxjs/operators';
const source = of(1, 2, 3);
source.pipe(
concatMap(x => interval(1000).pipe(take(2))) // 每个数字发出两个
).subscribe(console.log);
// 输出: 0, 1, 0, 1, 0, 1(延迟一秒)