头图

Project each source value to the same Observable, which is flattened multiple times using switchMap in the output Observable.

Input an Observable and output a function Operator. It is actually a function. Every time a value is emitted on the source Observable, the function returns a new Observable.

This function emits items from the given innerObservable and only gets the value from the most recently projected inner Observable.

Look at an example:

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));

Output:

After each click, the PointerEvent thrown by click$ is discarded by the Function Operator returned by switchMapTo. Finally, in the result function that the user subscribes to, the value printed is the value emitted by the interval(1000) Observable input by switchMapTo, instead of the PointerEvent thrown by clicks$.

Let's look at another example of displaying a countdown number on a web page.

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));

The initial integer is 10, and it decreases by one every 2 seconds, and stops when it decreases to -10.

Idea: The operation that triggers the counter to start decrementing is to click the screen, so you need to use fromEvent to construct Observable: click$

Perform an operation every two seconds, so you need to use interval to construct a second Observable.

Once the counter is started, the decrement operation needs to be performed every two seconds, so you need to use switchMapTo to map click$ to interval Observable.

After the value is passed, it has nothing to do with click$.

Because it is a decrement operation, which implies that this is a stateful scenario, the scan operator is chosen to maintain the internal state.

More original articles by Jerry, all in: "Wang Zixi":


注销
1k 声望1.6k 粉丝

invalid