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á.
