将每个源值投影到同一个 Observable,该 Observable 在输入 Observable 中应用 switchMap 屡次展平。
输出一个 Observable,输入一个 function Operator. 理论是一个函数,每次在源 Observable 上收回值时,该函数都会返回一个 新的 Observable.
该函数从给定的 innerObservable 收回我的项目,并且仅从最近投影的外部 Observable 中获取值。
看个例子:
import {EMPTY, range} from 'rxjs';
import {first, take, tap} from 'rxjs/operators';
import {fromEvent, interval} from 'rxjs';
import {switchMapTo} from 'rxjs/operators';
const clicks = fromEvent(document, 'click');
const test = event => console.log('Jerry:', event);
const result = clicks.pipe(tap(test),
switchMapTo(interval(1000))
);
result.subscribe(x => console.log(x));
输入:
每次点击之后,click$ 抛出的 PointerEvent,被 switchMapTo 返回的 Function Operator 抛弃了。最初用户订阅 result 函数里,打印的值,是 switchMapTo 输出的 interval(1000) Observable 发射的值,而不再是 clicks$ 抛出的 PointerEvent.
再看另一个在网页显示倒计时数字的例子。
import './style.css';
import {interval, fromEvent} from 'rxjs';
import {
switchMapTo,
scan,
startWith,
takeWhile,
finalize
} from 'rxjs/operators';
const COUNTDOWN_TIME = 10;
// reference
const countdownElem = document.getElementById('countdown');
// streams
const click$ = fromEvent(document, 'click');
const countdown$ = interval(2000).pipe(scan((acc, _) => --acc, COUNTDOWN_TIME),
startWith(COUNTDOWN_TIME)
);
click$
.pipe(switchMapTo(countdown$),
takeWhile(val => val >= -10),
finalize(() => (countdownElem.innerHTML = "We're done here!"))
)
.subscribe((val: any) => (countdownElem.innerHTML = val));
初始整数是 10,每隔 2 秒钟减一,减到 -10 时进行。
思路:触发计数器开始递加的操作是点击屏幕,因而须要应用 fromEvent 来结构 Observable:click$
每隔两秒钟执行某项操作,因而须要用 interval 结构第二个 Observable.
一旦计数器启动之后,每隔两秒钟须要执行递加操作,因而须要用 switchMapTo,将 click$ 映射成 interval Observable.
之后的值传递,就和 click$ 再无任何关联了。
因为是递加操作,暗示这是一个 stateful 场景,故选用 scan 操作符保护外部状态。
更多 Jerry 的原创文章,尽在:” 汪子熙 ”: