1
votes

comment annuler une demande imbriquée avec rxjs

buttonClicked$.pipe(
switchMap(value=>makeRequest1),
switchMap(responseOfRequest1=>makeRequest2))
.subscribe()
I need to make 2 http request sequentially, and abort downstream pending request  if the button clicks. Is the above code the right approach? I understand that a new click will cancel pending request1. if the click happens during request2, does request2 get canceled as well?

0 commentaires

3 Réponses :


2
votes

Pourquoi le deuxième switchMap peut ne pas être annulé

L'opérateur switchMap annule son Observable interne uniquement lorsqu'il reçoit l'événement suivant de son Observable amont (c'est-à-dire makeRequest1 ) , pas lorsque la source Observable émet (ie buttonClicked $ ). Considérez donc la séquence d'événements suivante:

buttonClicked$.pipe(
  switchMap(clickValue => makeRequest1(clickValue).pipe(
    mergeMap(request1Value => makeRequest2(request1Value)))
).subscribe(request2Value => /* ... */);

Dans ce scénario, car la réponse à la requête 2 est reçue avant que la deuxième réponse à la requête 1 ne soit reçue, même si le deuxième bouton clique s'est produite avant la fin de la requête 2, la requête 2 n'a jamais été annulée.

Si la requête 1 émet sa deuxième réponse avant que la requête 2 ne reçoive une réponse, alors oui, la requête 2 est annulée. Mais notez que ce n'est pas le clic sur le bouton qui l'a annulé en soi, c'est l'émission de la requête 1 qui l'a annulée.

La solution

Si vous souhaitez annuler les deux requêtes de manière fiable lorsque le est cliqué sur le bouton, les deux demandes doivent être effectuées dans la même switchMap:

first button click
first request 1 sent
first response to request 1 received
first request 2 sent
second button click
second request 1 sent
first response to request 2 received
second response to request 1 received

0 commentaires

0
votes

Oui, ça marche comme ça avec intervalle. Je ne l'ai pas testé avec une requête réseau.

À chaque clic, le deuxième intervalle observable est redémarré.

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
<button id="btn">Click Me</button>

<div id="result"></div>
const { fromEvent, interval, of } = rxjs;
const { switchMap } = rxjs.operators;

const btn = document.getElementById('btn');
const result = document.getElementById('result');
const click$ = fromEvent(btn, 'click');

click$
	.pipe(
  	switchMap(value => of('Hello')),
  	switchMap(value => interval(1000))
  )
  .subscribe(
  	val => result.innerText = val
  )


0 commentaires

1
votes

Ce comportement est correct car switchMap se désabonne de son Observable interne uniquement lorsqu'il reçoit la notification next . Cela signifie que lorsque vous avez deux switchMap , alors le premier doit émettre en premier pour déclencher la désinscription dans le second.

Vous pouvez éviter cela en utilisant un seul switchMap code > et mettre le deuxième appel makeRequest2 dans une seule chaîne avec makeRequest1 .

buttonClicked$.pipe(
  switchMap(value => makeRequest1(value).pipe(
    mergeMap(responseOfRequest1 => makeRequest2(responseOfRequest1)),
  )),
  .subscribe()

De cette façon, lorsque buttonCliqué $ émet qu'il fait switchMap se désabonner de son Observable interne qui se désabonne également en interne mergeMap qui annulera le deuxième appel s'il est toujours en attente.

p>


0 commentaires