乐趣区

关于rxjs:RxJs-SwitchMap-学习笔记

网址:https://www.learnrxjs.io/lear…

The main difference between switchMap and other flattening operators is the cancelling effect. On each emission the previous inner observable (the result of the function you supplied) is cancelled and the new observable is subscribed. You can remember this by the phrase switch to a new observable.

switchMap 和其余扁平化操作符的次要区别在于勾销成果。在每次发射时,先前的外部 observable(您提供的函数的后果)被勾销并订阅新的 observable。您能够通过短语 switch to a new observable 记住这一点。

This works perfectly for scenarios like typeaheads where you are no longer concerned with the response of the previous request when a new input arrives. This also is a safe option in situations where a long lived inner observable could cause memory leaks, for instance if you used mergeMap with an interval and forgot to properly dispose of inner subscriptions. Remember, switchMap maintains only one inner subscription at a time, this can be seen clearly in the first example.

这对于像事后输出这样的场景十分无效,当新输出达到时,您不再关怀先前申请的响应。在长期存在的外部 observable 可能导致内存透露的状况下,这也是一个平安的抉择。

Be careful though, you probably want to avoid switchMap in scenarios where every request needs to complete, think writes to a database. switchMap could cancel a request if the source emits quickly enough. In these scenarios mergeMap is the correct option.

然而要小心,您可能心愿在每个申请都须要实现的状况下防止应用 switchMap,比方写入数据库的场景。如果源收回足够快,switchMap 能够勾销申请。在这些状况下,mergeMap 是正确的选项。

看这个例子:

import {interval, fromEvent} from 'rxjs';
import {switchMap} from 'rxjs/operators';

fromEvent(document, 'click')
.pipe(
  // restart counter on every click
  switchMap(() => interval(1000))
)
.subscribe(console.log);

每次点击屏幕之后,fromEvent issue 进去的 MouseEvent,传入 switchMap 外部,都会重启一个新的工夫距离为 1 秒的计时器,并且勾销之前的定时器。打印如下:

再看一个实现定时器的例子:

import {Component, OnInit} from '@angular/core';
import {interval, fromEvent, merge, empty} from 'rxjs';
import {switchMap, scan, takeWhile, startWith, mapTo} from 'rxjs/operators';

const COUNTDOWN_SECONDS = 1000;

@Component({
  selector: 'switchMap-study',
  templateUrl: './switchMap.component.html'
})
export class SwitchMapComponent implements OnInit {ngOnInit(): void {

    // elem refs
    const remainingLabel = document.getElementById('remaining');
    const pauseButton = document.getElementById('pause');
    const resumeButton = document.getElementById('resume');

    // streams
    const interval$ = interval(1000).pipe(mapTo(-1));
    const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
    const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));

    const timer$ = merge(pause$, resume$).pipe(startWith(true),
        switchMap(val => (val ? interval$ : empty())),
        scan((acc, curr) => (curr ? curr + acc : acc), COUNTDOWN_SECONDS),
        takeWhile(v => v >= 0)).subscribe((val: any) => (remainingLabel.innerHTML = val));
    }
}
<h1>Switch Map Study</h1>

<a href="https://www.learnrxjs.io/learn-rxjs/operators/transformation/switchmap">Document</a>

<h4>
    Time remaining: <span id="remaining"></span>
    </h4>
    <button id="pause">
    Pause Timer
    </button>
    <button id="resume">
    Resume Timer
</button>

刚开始时,startWith true,因而 switchMap 得以继续下去。switchMap 传入的 project,承受的参数 val 是 boolean 类型,返回一个新的 Observable,即 internal$.

留神 empty() 的用法,返回一个类型为 never 的 Observable.

Creates an Observable that emits no items to the Observer and immediately emits a complete notification.

Just emits ‘complete’, and nothing else.

This static operator is useful for creating a simple Observable that only emits the complete notification. It can be used for composing with other Observables, such as in a mergeMap.

单步调试点了 pause 之后:

第 41 行 unsubscribe 办法,体现了 switchMap 主动勾销先前的外部 observable 的个性:

先 cancel,再订阅新的 Observable:

如果返回 empty,就不会再执行后续的 scan 了:

能够把 switchMap 输出参数,即 projection 进行革新:

该 projection 的类型是一个箭头函数,输出参数是一个 boolean,输入是一个新的 Observable.

更多 Jerry 的原创文章,尽在:” 汪子熙 ”:

退出移动版