Búsqueda de sitios web

typescript - Cancelar solicitudes previas no idénticas en Angular


Estoy intentando obtener datos para un mapa de Leaflet en una aplicación Angular. Para cada nivel de zoom necesito datos de diferente resolución, por lo que en moveend hago otra llamada al backend.

mapa.componente

    // Every time a movement is done on the map the calls are done again.
    this.map.on('moveend', () => {
      this.mapService.drawHeatMap();
    });

map.service.ts

  public drawHeatMap(): void {
    this.fetchData().subscribe((data) => {
      // DO STUFF WITH DATA
    });
  }
private fetchData(): Observable<Leaflet.HeatLatLngTuple[]> {
    return this.http.get<ResponseType>(URL).pipe(
      map(({ data }: ResponseType) => {
        return data.map((data: any) => {
          // PARSE DATA
        });
      })
    );
  }

Durante las pruebas, vi que al desplazarse hacia dentro y hacia fuera con frecuencia hace que las llamadas a mi API se acumulen, lo cual es algo que quiero evitar.

Cuando intenté cancelar llamadas pendientes con switchMap(), no obtengo el resultado deseado porque las llamadas no son idénticas...

Ejemplos de URLs de solicitud de dos llamadas diferentes:

.../api/ZoomLevel=10&swLong=3&neLong=5&swLat=50&neLat=51
.../api/ZoomLevel=11&swLong=2&neLong=4&swLat=49&neLat=50

Ayudar a cancelar la llamada anterior aunque no sea idéntica sería muy apreciado.

Respuesta #1

Lo que está pasando ahora es que estás haciendo llamadas en cada evento. En otras palabras, creando streams. En su lugar, quieres un solo stream, para poder cancelar la llamada anterior.

mapa.componente

fromEvent(this.map, 'moveend').pipe(
  switchMap(() => this.mapService.drawHeatMap())
).subscribe();

map.service.ts

  public drawHeatMap(): void {
    return this.fetchData();
  }

p.d. obviamente no he probado, así que no estoy seguro de si fromEvent(this.map, 'moveend') es la manera correcta de obtener ese flujo externo. Por favor, proporciona la API de this.map para posiblemente una respuesta más detallada.

Respuesta #2

Eso sucede porque la solicitud HTTP observable y la del evento, no están encadenadas entre sí con un pipe y un subscribe.

Además, es mejor en este tipo de evento usar el operador debounceTime de RxJS para reducir el número de llamadas HTTP.

Puedes probar lo siguiente:

fromEvent(this.map, 'moveend')
  .pipe(
    debounceTime(300), // This will prevent calling the drawHeatMap within 300ms more than one time.
    switchMap(() => this.mapService.drawHeatMap())
  )
  .subscribe();

Y dentro de tu map.service:

public drawHeatMap(): Observable<any> {
  return this.fetchData().pipe(
    tap((data) => {
      // DO STUFF WITH DATA
    })
  );
}