Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

298
Visualizações
Rxjs - Chain http calls with Observables

I want to make 3 http calls which returns a boolean value. What I want is to make the next call only if the result of the previos call is true

IE:
call1() -> if false, stop, if true:
call2() -> if false, stop, if true:
call3()

now read results in a way that indicates which call returned false if so.

my first attemp with switchMap:

    this.call1()
      .pipe(
        switchMap((r1) => (r1 ? this.call2() : of(false))),
        switchMap((r2) => (r2 ? this.call3() : of(false)))
      )
      .subscribe((r) => {
        console.log('inside subscribe:', r);
      });

the problem here that now inside the subscribe I get:
'inside subscribe:' false
and I can't know if the false result is from call1,2 or 3.

so my solution is to save the results in external array, like so:

    // seriel execution with switchMap, we can use each result to the next call
    // + save all results
    const results = [false, false, false];
    this.call1()
      .pipe(
        // save stage1 result
        tap(r1 => results[0] = r1),
        // if true, make call2, else return false
        switchMap((r1) => (r1 ? this.call2() : of(false))),
        // save stage2 result
        tap(r2 => results[1] = r2),
        // if true, make call3, else return false
        switchMap((r2) => (r2 ? this.call3() : of(false))),
        // save stage3 result
        tap(r3 => results[2] = r3),
      )
      .subscribe((r) => {
        console.log('inside subscribe:', r); // r is the latest value results[2]
        console.log('all results:', results) // array of all stages [true,false,false]
      });

  }

and it seems to work, but maybe there is another way without external work? only with rxjs operators?

StackBlitz link:
https://stackblitz.com/edit/angular-rxjs-playground-zjnh7u?devtoolsheight=33&file=app/app.component.ts

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Maybe something like this can work

this.call1()
  .pipe(
    switchMap((r1) => (r1 ? this.call2() : 
             of(false).pipe(tap(() => console.log('r1 returns false')),
    switchMap((r2) => (r2 ? this.call3() : 
             of(false).pipe(tap(() => console.log('r2 returns false'))),
    tap(respOfR3 => if(!respOfR3) {console.log('r3 returns false')})
  )
  .subscribe((r) => {
    console.log('inside subscribe:', r);
  });

At the same time consider that the sequence of booleans notified by your first Observable implicitly contains the info you are looking for. In fact the position of the first false you encounter reflects the first call that has returned false.

over 4 years ago · Santiago Trujillo Relatório

0

I would attach the source to the outcome - simplest thing is a tuple [number, boolean], where the first element in the tuple/array is the source. A variation of the switchMap solution is:

    this.call1()
      .pipe(
        map((result) => [1, result]),
        switchMap((r1) => (r1[1] ? this.call2().pipe(map((result) => [2, result])) : of(r1))),
        switchMap((r2) => (r2[1] ? this.call3().pipe(map((result) => [3, result])) : of(r2)))
      )
      .subscribe((r) => {
        console.log('inside subscribe:', r);
      });

This has a pattern and is a bit verbose, we can do better:

    function attachSource(source: number, target: Observable<boolean>): Observable<[number, boolean]> {
      return target.pipe(map((result) => [source, result]));
    }

    attachSource(1, this.call1())
      .pipe(
        switchMap((r1) => (r1[1] ? attachSource(2, this.call2()) : of(r1))),
        switchMap((r2) => (r2[1] ? attachSource(3, this.call3()) : of(r2)))
      )
      .subscribe((r) => {
        console.log('inside subscribe (try2):', r);
      });

And if we generalize a little more, given the following:

    function attachSource<T>(source: number, target: () => Observable<T>): Observable<[number, T]> {
      return target().pipe(map((result) => [source, result]));
    }

    function series<T>(failed: (arg: T) => boolean, ...factories: (() => Observable<T>)[]): Observable<[number, T]> {
      return factories.reduce((agr, cur, index) => {
        if (index === 0) {
          return attachSource(index+1, cur);
        } else {
          return agr.pipe(switchMap((prevResult) => failed(prevResult[1]) ? of(prevResult) : attachSource(index+1, cur)));
        }
      }, empty<[number, T]>());
    }

It can be as simple as:

    series((x: boolean) => x, this.call1.bind(this), this.call2.bind(this), this.call3.bind(this))
      .subscribe((r) => {
        console.log('inside subscribe (try3):', r);
      });
over 4 years ago · Santiago Trujillo Relatório

0

Here is a very clean solution using expand operator for recursive calls

const results = [false, false, false];
let count = 0;
this.call().pipe(
    tap(response => {
      results[count] = response
      count++
      }
    ),
    expand((response) => response && count < 3
               ? this.call()
               : EMPTY
    )
).subscribe((r) => {
    console.log('inside subscribe:', r); // r is the latest value results[2]
    console.log('all results:', results) // array of all stages [true,false,false]
});

And you don't really need multiple call function (call1, call2, call3), only one will be enough

call(): Observable<boolean> {
 let bool: boolean = this.randBool();
 return of(bool);
}

private randBool(): boolean {
  return Math.random() < 0.5
}

https://stackblitz.com/edit/angular-rxjs-playground-zvfpay?file=app/app.component.ts

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda