【问题标题】:RxJs: Can you spread operators as arguments into pipe operatorRxJs:您可以将运算符作为参数传播到管道运算符中吗
【发布时间】:2020-05-25 17:45:24
【问题描述】:

我有两个可观察的流,它们执行非常独立的映射逻辑,但最终以以下 3 个运算符结束:

  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..的这个错误。

【问题讨论】:

    标签: rxjs rxjs-pipeable-operators rxjs-observables


    【解决方案1】:

    你可以尝试使用原生.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])
          );
    

    【讨论】:

    • 非常感谢,所有这些都奏效了。为简单起见,我选择了中间选项。
    【解决方案2】:

    您可以尝试一种反应式方法(除非真正隔离,否则没有副作用):

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

    【讨论】:

      【解决方案3】:

      我希望这个答案能帮助任何偶然发现这个问题的人。接受的答案对我来说并不完全有效,主要原因是null 被作为.apply() 的第一个参数而不是我的可观察函数再次传递。这是一个类似于我在项目中成功实现的示例。

      private pipeActions = [
         filter(...),
         map(...),
      ];
      
      private myObservable = combineLatest(...);
      
      doThing(): Observable<any> {
         return this.myObservable
            .pipe.apply(this.myObservable, [...this.pipeActions]);
      }
      
      doOtherThing(): Observable<any> {
         return this.myObservable
            .pipe.apply(
               this.myObservable,
               [...this.pipeActions, map(...)], // Do something additionally after my list of pipe actions
            );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-23
        • 1970-01-01
        • 2018-07-06
        • 2017-11-18
        • 2018-03-27
        • 2018-04-28
        • 1970-01-01
        相关资源
        最近更新 更多