Quiero resolver un observable pero no quiero que el valor de retorno reemplace el valor anterior en la tubería. ¿Hay alguna tap() asincrónica? Necesito un operador como switchMap pero quiero ignorar el retorno.

of(1).pipe(switchMap(() => of(2))).subscribe(console.log); // expected: 1

Podría crear un operador personalizado, pero seguro que hay algo incorporado en rxjs.

4
Gabriel Llamas 23 feb. 2018 a las 01:21

4 respuestas

La mejor respuesta

Terminé con este operador personalizado. Es como tocar pero resuelve observables (y debe actualizarse para que también sea compatible con las promesas).

export function switchTap<T, R>(next: (x: T) => Observable<R>): MonoTypeOperatorFunction<T>;
export function switchTap<R>(observable: Observable<R>): MonoTypeOperatorFunction<R>;
export function switchTap<T, R>(
  arg: Observable<T> | ((x: T) => Observable<R>)
): MonoTypeOperatorFunction<T> {
  const next: (x: any) => Observable<T | R> =
    typeof arg === 'function' ? arg : (x: any): Observable<T> => arg;
  return switchMap<T, T>(value => next(value).pipe(ignoreElements(), concat(of(value))));
}

Uso:

of(1).pipe(switchTap(of(2))).subscribe(console.log) // 1

O con una función:

of(1)
      .pipe(
        switchTap(value => {
          console.log(value); // value: 1
          return of(value + 1);
        })
      )
      .subscribe(console.log); // 1
6
Gabriel Llamas 23 ago. 2018 a las 05:34

Si solo quiere ignorar los valores de la suscripción, simplemente no pase ningún argumento en la devolución de llamada subscribe:

of(1).pipe(switchMap(() => of(2))).subscribe(()=>{
    console.log('no arguments')
});

Sin embargo, si desea retener los valores del primer observable, las cosas pueden ser complicadas. Una forma es usar Subject para retener el valor:

//create a BehaviorSubject
var cache = new BehaviorSubject<any>(0);

of(1).pipe(switchMap((first) => {
    cache.next(first);
    return of(2);
})).subscribe(() => {
    console.log(cache.value) //gives 1
});

O puede usar .map() para alterar los valores. Esto es algo hacky y el código es más difícil de mantener:

of(1).pipe(switchMap((first) => {
    return of(2).map(() => first);
})).subscribe((second) => {
    console.log(second) //gives 1 because the values was mapped
});
2
CozyAzure 23 feb. 2018 a las 03:05

Lo hago asi

of(2).pipe(
   switchMap( num => this.doSmtg(num), num => num)
).subscribe(num => console.log(num)); // 2

El segundo parámetro de switchmap recibe dos valores, el que se pasa a this.doSmtg y el valor devuelto por el observable de doSmtg (num).

0
Ced 12 mar. 2019 a las 16:14

Para cualquier persona nueva que tenga el mismo problema, recomendaría usar el parámetro resultSelector compatible con switchMap y otros operadores de mapeo RxJS.

Ejemplo:

switchMap(1 => of(2), (one, two) => one)

Para leer más: https://www.learnrxjs.io/operators/transformation/mergemap. html

0
mortom123 25 nov. 2019 a las 21:51