Cancele una solicitud HTTP cuando otra persona llame al mismo método -- angular campo con rxjs camp Relacionados El problema

Cancel an HTTP request when someone else call same method


0
vote

problema

Español

Estoy usando angular, ngrx y rxjs en mi solicitud. Cuando se llama un efecto dos veces, la primera solicitud HTTP de efecto se cancela, y solo se cuenta la segunda.

Quiero emular esto en una función que está fuera del alcance de NGRX.

Tengo el siguiente método:

  checkMissionPoint(     positions: Array<Cesium.Cartographic>   ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>;   }> {      return this.store$.pipe(       select(TransactionsStoreSelectors.selectedTransactionId),       take(1),       switchMap((tId) =>         this.httpClient           .post<Array<CheckWaypointResponse>>(             HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`),             {positions}           )           .pipe(             switchMap((result) => {               return result;             })           )       )     );   }   

Llame a este método como este en mi aplicación en varios lugares en la aplicación

      this.missionHelperService.checkMissionPoint(positions)   

Ahora, conozco una manera fea de cancelarla, manteniendo una referencia y cancelación de suscripción si se llama nuevamente el método y la referencia aún existe. Pero me pregunto si hay una buena manera de lograr esto.

gracias.

Editar: Hice un pequeño StackBlitz, pero necesitas configurar la conexión 3G lenta en tu consola de cromo https: // angular-xm2ixt.stackblitz.io

Notará que el OBS se llama dos veces, la API disparará y responderá, lo que quiero es la segunda llamada Cancelar la primera (y enviar un error a quién escuchando, y la Sub 2 irá a lo normal)

Original en ingles

I am using angular, ngrx and rxjs in my application. When an effect is called twice, the first effect http request is canceled, and only the second one is counted.

I want to emulate this in a function that is outside ngrx scope.

I have the following method :

checkMissionPoint(     positions: Array<Cesium.Cartographic>   ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>;   }> {      return this.store$.pipe(       select(TransactionsStoreSelectors.selectedTransactionId),       take(1),       switchMap((tId) =>         this.httpClient           .post<Array<CheckWaypointResponse>>(             HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`),             {positions}           )           .pipe(             switchMap((result) => {               return result;             })           )       )     );   } 

I call this method like this in my app in various place in the application

    this.missionHelperService.checkMissionPoint(positions) 

Now, I know some ugly way to cancel it, by keeping like a reference and unsubscribing if the method is called again and the reference still exist. But I am wondering if there is a nice rxjs way to achieve this.

Thanks.

EDIT : I made a small stackblitz but you need to setup SLOW 3G connection in your chrome console https://angular-xm2ixt.stackblitz.io

you will notice that the obs is called twice, the api will both fire and answer, what I want is the second call cancel the first (and dispatch an error to who was listening, and sub 2 will go trought has normal)

     
   
   

Lista de respuestas

1
 
vote
vote
La mejor respuesta
 

Tuve una situación muy similar, así es como lo solucioné.

  checkMissionPointCalled = new EventEmitter<void>();  checkMissionPoint(     positions: Array<Cesium.Cartographic> ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>; }> {     this.checkMissionPointCalled.emit();     return this.store$.pipe(         select(TransactionsStoreSelectors.selectedTransactionId),         take(1),         switchMap((tId) =>             this.httpClient                 .post<Array<CheckWaypointResponse>>(                      HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`),                         { positions }                 )          ),         takeUntil(this.checkMissionPointCalled)     ); }   

Sin embargo, no pude obtener el uso de

           .pipe(             switchMap((result) => {               return result;             })           )   

Después de httpClient.post Llame, creo que probablemente esto fue un error. Entonces, no lo he incluido en mi respuesta.

Es probable que también desee cerrar checkMissionPointCalled en ngOnDestroy MÉTODO.

 

I had a very similar situation, this is how i solved it.

checkMissionPointCalled = new EventEmitter<void>();  checkMissionPoint(     positions: Array<Cesium.Cartographic> ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>; }> {     this.checkMissionPointCalled.emit();     return this.store$.pipe(         select(TransactionsStoreSelectors.selectedTransactionId),         take(1),         switchMap((tId) =>             this.httpClient                 .post<Array<CheckWaypointResponse>>(                      HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`),                         { positions }                 )          ),         takeUntil(this.checkMissionPointCalled)     ); } 

However, i was not able to get the use of

         .pipe(             switchMap((result) => {               return result;             })           ) 

after httpClient.post call, i think probably this was an error. So, haven't included it in my answer.

You will probably also want to close checkMissionPointCalled in ngOnDestroy method.

 
 
   
   
1
 
vote

El problema que tiene ahora, es que el método switchMap()5 devuelve un nuevo observable para cada persona que llama.

Creo que podrías lograr lo que estás tratando de hacer si tuviste un observable privado y devolviste ese mismo observable para todas las personas que llaman. Este observable usaría switchMap() para lograr el comportamiento de cancelación que está buscando.

  private positions$ = new Subject(); private uri$ = this.store$.pipe(     select(TransactionsStoreSelectors.selectedTransactionId),     map(tId => HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`) ); private checkMissionPoint$ = combineLatest([this.uri$, this.positions$]).pipe(     switchMap(([uri, positions]) => this.httpClient.post<CheckWaypointResponse[]>(uri, {positions})) );  checkMissionPoint(     positions: Array<Cesium.Cartographic>   ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>;   }> {     this.positions.next(positions);      return this.checkMissionPoint$.pipe(       take(1)     ); }   

Dependiendo de su caso de uso, puede ser más limpio que la devolución del método void y haga el público observable común:

  private positions$ = new Subject(); private uri$ = this.store$.pipe(     select(TransactionsStoreSelectors.selectedTransactionId),     map(tId => HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`) ); public missionPoint$ = combineLatest([this.uri$, this.positions$]).pipe(     switchMap(([uri, positions]) => this.httpClient.post<CheckWaypointResponse[]>(uri, {positions})) );  setPosition(     positions: Array<Cesium.Cartographic>   ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>;   }> {     this.positions.next(positions); }   
 

The problem you have now, is that the checkMissionPoint() method returns a brand new observable for every caller.

I think you could achieve what your are trying to do if you had a private observable and returned that same observable to all callers. This observable would use switchMap() to achieve the cancelling behavior you are looking for.

private positions$ = new Subject(); private uri$ = this.store$.pipe(     select(TransactionsStoreSelectors.selectedTransactionId),     map(tId => HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`) ); private checkMissionPoint$ = combineLatest([this.uri$, this.positions$]).pipe(     switchMap(([uri, positions]) => this.httpClient.post<CheckWaypointResponse[]>(uri, {positions})) );  checkMissionPoint(     positions: Array<Cesium.Cartographic>   ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>;   }> {     this.positions.next(positions);      return this.checkMissionPoint$.pipe(       take(1)     ); } 

Depending on your use case, it may be cleaner to have the method return void and make the common observable public:

private positions$ = new Subject(); private uri$ = this.store$.pipe(     select(TransactionsStoreSelectors.selectedTransactionId),     map(tId => HTTPUtils.getPath(`${environment.FLIGHT_URL}/trajectories/${tId}/checkpoints`) ); public missionPoint$ = combineLatest([this.uri$, this.positions$]).pipe(     switchMap(([uri, positions]) => this.httpClient.post<CheckWaypointResponse[]>(uri, {positions})) );  setPosition(     positions: Array<Cesium.Cartographic>   ): Observable<{     valid: boolean;     response: Array<CheckWaypointResponse>;   }> {     this.positions.next(positions); } 
 
 
     
     

Relacionados problema

2  RXJS: Trabajando en Groupby y observable.Fromvents en Nodejs  ( Rxjs working on groupby and observable fromevents in nodejs ) 
Estoy muy impresionado con RXJS y en realidad comienza a trabajar en eso. Sin embargo, mi siguiente código NODEJS no funciona como se espera al menos para mí....

2  rxjs una secuencia múltiples suscripciones toman x  ( Rxjs one sequence multiple subscriptions take x ) 
Digamos que tengo un observable RXJS creado a partir de una matriz de valores: let obs = Observable.fromArray([1,2,3,4,5,6]); En algún botón, hacemos e...

45  Manejo de tokens de refrescar usando RXJS  ( Handling refresh tokens using rxjs ) 
Desde que comencé con angular2, he configurado mis servicios para devolver a la observable de T. En el servicio, tendría la llamada MAP (), y los componentes ...

0  Cómo enlazar la casilla de verificación para volver a calcular los datos dinámicos en el script de tipo angular 6  ( How to bind checkbox to recalculate dynamic data in angular 6 using type script ) 
Quería manipular los resultados de los datos cuando se cambia el evento de la casilla de verificación. Poloqué los datos dinámicos en una tabla y me deben fil...

0  Ejecutar alguna función al llegar a un nuevo observador en un comportamiento angular  ( Execute some function on arriving a new observer in angular behaviorsubject ) 
Me gustaría ejecutar alguna función cuando un nuevo observador llega por un comportamiento en angular. export class MyClass { public bs: BehaviorSubject<...

3  Angular 7 propiedad 'Share' no existe en tipo observable  ( Angular 7 property share does not exists in type observable ) 
Estaba escribiendo CachcingserviceBase en Angular 7, pero el siguiente error parece ser presionado "La participación observable no es una función" $("#lobb...

0  ¿Es posible actualizar observable con datos propios en Angular2 / TyperScript?  ( Is it possible to update observable with own data in angular2 typescript ) 
Tengo un NGFOR con ASYNC así: <div *ngFor="let location of googleSearchLocations | async"> <div *ngFor="let location of facebookSearchLocations | async"> ...

242  ¿Es necesario cancelar la suscripción de los observables creados por los métodos HTTP?  ( Is it necessary to unsubscribe from observables created by http methods ) 
¿Necesita cancelar la suscripción de las llamadas HTTP angular 2 para evitar la pérdida de memoria? fetchFilm(index) { var sub = this._http.get(`h...

0  Combinar la promesa con observable  ( Merge promise with observable ) 
Aquí está el extracto de mi servicio, me gustaría getIssues METOD para devolver a observar, en lugar de prometer resolverse en observable, ya que parece muc...

8  Angular2: Captura 401 Error para la actualización del token  ( Angular2 catching 401 error for token refresh ) 
Soy nuevo en Angular2 e intentando el error 401 Error de Token Actualizar con el plan para reintentar la solicitud original ... Aquí está mi método AuthServ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos