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?
3 Réponses :
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.
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
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 )
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>