Búsqueda de sitios web

typescript - Cómo cancelar/cancelar la suscripción de todas las solicitudes HTTP pendientes en Angular 4+


Cómo cancelar/interrumpir todas las solicitudes HTTP pendientes en Angular 4+.

Existe un método unsubscribe para cancelar solicitudes HTTP, pero cómo cancelar todas las solicitudes pendientes a la vez.

Especialmente durante el cambio de ruta.

Hay una cosa que hice

ngOnDestroy() {
  this.subscription.unsubscribe();
}

pero cómo lograr esto a nivel mundial

¿Alguna idea?

Respuesta #1

Consulta el operador takeUntil() de RxJS para cancelar globalmente tus suscripciones :

- RxJS 6+ (usando la sintaxis pipe)

import { takeUntil } from 'rxjs/operators';

export class YourComponent {
   protected ngUnsubscribe: Subject<void> = new Subject<void>();

   [...]

   public httpGet(): void {
      this.http.get()
          .pipe( takeUntil(this.ngUnsubscribe) )
          .subscribe( (data) => { ... });
   }

   public ngOnDestroy(): void {
       // This aborts all HTTP requests.
       this.ngUnsubscribe.next();
       // This completes the subject properlly.
       this.ngUnsubscribe.complete();
   }
}

- RxJS < 6

import 'rxjs/add/operator/takeUntil'

export class YourComponent {
   protected ngUnsubscribe: Subject<void> = new Subject<void>();

   [...]

   public httpGet(): void {
      this.http.get()
         .takeUntil(this.ngUnsubscribe)
         .subscribe( (data) => { ... })
   }

   public ngOnDestroy(): void {
       this.ngUnsubscribe.next();
       this.ngUnsubscribe.complete();
   }
}

Básicamente, puedes emitir un evento en tu Subject de cancelación de suscripción usando next() cada vez que quieras completar un conjunto de streams. También es una buena práctica cancelar la suscripción a los Observables activos cuando el componente se destruye, para evitar fugas de memoria.

Vale la pena leer:

  • Evitar tomar hasta que haya fugas

  • Una gran respuesta de seangwright

Respuesta #2

Puedes crear un interceptor para aplicar el operador takeUntil a cada solicitud. Luego, al cambiar de ruta, emitirás un evento que cancelará todas las solicitudes pendientes.

@Injectable()
export class HttpCancelInterceptor implements HttpInterceptor {
  constructor(private httpCancelService: HttpCancelService) { }

  intercept<T>(req: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {
    return next.handle(req).pipe(takeUntil(this.httpCancelService.onCancelPendingRequests()))
  }
}

Servicio de ayuda.

@Injectable()
export class HttpCancelService {
  private cancelPendingRequests$ = new Subject<void>()

  constructor() { }

  /** Cancels all pending Http requests. */
  public cancelPendingRequests() {
    this.cancelPendingRequests$.next()
  }

  public onCancelPendingRequests() {
    return this.cancelPendingRequests$.asObservable()
  }

}

Engancha en los cambios de ruta en algún lugar de tu aplicación (por ejemplo, en onInit en appComponent).

this.router.events.subscribe(event => {
  if (event instanceof ActivationEnd) {
    this.httpCancelService.cancelPendingRequests()
  }
})

Y por último, pero no menos importante, registra el interceptor en tu app.module.ts:

  import { HttpCancelInterceptor } from 'path/to/http-cancel.interceptor';
  import { HTTP_INTERCEPTORS } from '@angular/common/http';

  @NgModule({
    [...]
    providers: [
      {
        multi: true,
        provide: HTTP_INTERCEPTORS,
        useClass: HttpCancelInterceptor
      }
    ],
    [...]
  })
  export class AppModule { }

Respuesta #3

Si no quieres darte de baja manualmente de todas las suscripciones, entonces puedes hacer esto:

export function AutoUnsubscribe(constructor) {

  const original = constructor.prototype.ngOnDestroy;

  constructor.prototype.ngOnDestroy = function() {
    for (const prop in this) {
      if (prop) {
        const property = this[prop];
        if (property && (typeof property.unsubscribe === 'function')) {
          property.unsubscribe();
        }
      }
    }

    if (original && typeof original === 'function') {
      original.apply(this, arguments)
    };
  };

}

Entonces puedes usarlo como decorador en tu componente

@AutoUnsubscribe
export class YourComponent  {
}

pero aún necesitas almacenar las suscripciones como propiedades del componente. Y cuando navegas fuera del componente, la función AutoUnsubscribe ocurrirá.

Artículos relacionados