RxJs: Можете ли вы распространять операторы в качестве аргументов в оператор конвейера

У меня есть два наблюдаемых потока, которые выполняют очень отдельную логику сопоставления, но в конечном итоге заканчиваются следующими тремя операторами:

  this.selection
    .pipe(
      ..Custom mapping operators
      tap(_ => this.devicesLoading = true),
      switchMap(d => this.mapService.findLocationForDevices(d)),
      map(loc => marker([loc.latitude, loc.longitude])
    )
    .subscribe(markers => this.plotMarkers(markers));

Я хочу переместить последние tap, switchMap, map операторы в общую функцию, чтобы я мог просто применить их в обоих моих наблюдаемых потоках.

Я думал о том, чтобы сделать:

  private resolveLocationsAndConvertToMarkers = (devices: String[]) => [
    tap(_ => this.devicesLoading = true),
    switchMap((devices: string[]) => this.mapService.findLocationForDevices(devices)),
    map(loc => marker([loc.latitude, loc.longitude])
  ];

Но я не был уверен, как распространить эти операторы на аргументы канала, например: #

      this.selection
        .pipe(
          // Custom mapping operators
          ... this.resolveLocationsAndConvertToMarkers
        )
        .subscribe(markers => this.plotMarkers(markers));

это ошибки, которые there are no overloads that expect 3 or 5 arguments ..


person MikeByte    schedule 10.02.2020    source источник


Ответы (2)


Вы можете попробовать использовать родной .apply()

this.selection
    .pipe.apply(null,this.resolveLocationsAndConvertToMarkers)

или оберните список операторов в pipe()

  private resolveLocationsAndConvertToMarkers = (devices: String[]) => pipe(
    tap(_ => this.devicesLoading = true),
    switchMap((devices: string[]) => this.mapService.findLocationForDevices(devices)),
    map(loc => marker([loc.latitude, loc.longitude])
  );

или вернуть функцию более высокого порядка

private resolveLocationsAndConvertToMarkers = (devices: String[]) => source=>source.pipe(
        tap(_ => this.devicesLoading = true),
        switchMap((devices: string[]) => this.mapService.findLocationForDevices(devices)),
        map(loc => marker([loc.latitude, loc.longitude])
      );
person Fan Cheung    schedule 10.02.2020
comment
Большое спасибо, все это сработало. Я выбрал средний вариант для простоты. - person MikeByte; 11.02.2020

Вы можете попробовать реактивный подход (без побочных эффектов, если он действительно не изолирован):

const preSelection$ = this.selection
  .pipe
  //..Custom mapping operators
  ();

const selection$: Observable<Marker> = preSelection$.pipe(
  switchMap(preSelection =>
    concat(
      of(null),
      of(preSelection).pipe(
        switchMap(d => this.mapService.findLocationForDevices(d)),
        map(loc => marker([loc.latitude, loc.longitude]))
      )
    )
  ),
  shareReplay({ bufferSize: 1, refCount: true })
);

const isLoading$: Observable<boolean> = selection$.pipe(map(x => !!x));

const sideEffectUpdatePlotMarkers$ = selection$.pipe(
  tap(markers => this.plotMarkers(markers))
);

// isolate `subscribe` calls and side effects as much as possible
sideEffectUpdatePlotMarkers$.subscribe();
person maxime1992    schedule 10.02.2020