web-dev-qa-db-fra.com

Comment annuler/désinscrire toutes les demandes HTTP en attente angulaires 4+

Comment annuler/abandonner toutes les demandes HTTP en attente angulaires 4+.

Il existe une méthode unsubscribe pour annuler les demandes HTTP mais comment annuler toutes les demandes en attente en même temps. 

Surtout pendant le changement de route.

Il y a une chose que j'ai faite 

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

mais comment y parvenir à l'échelle mondiale

Des idées?

18
Sibiraj

Consultez l'opérateur takeUntil() de RxJS pour supprimer globalement vos abonnements: 

- RxJS 6+ (utilisant la syntaxe 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();
   }
}

Vous pouvez essentiellement émettre un événement sur votre désinscription Subject en utilisant next() chaque fois que vous souhaitez compléter un ensemble de flux. Il est également recommandé de vous désabonner des observables actifs lors de la destruction du composant afin d'éviter les fuites de mémoire.

A lire:

24
Alexis Facques

Vous pouvez créer un intercepteur pour appliquer l'opérateur takeUntil à chaque demande. Ensuite, lors du changement de route, vous émettez une valeur qui annulera toutes les demandes en attente.

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

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

Service d'assistance.

@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()
  }

}

Accrochez-vous sur les changements de route quelque part dans votre application (par exemple, un composant d'application).

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

Si vous ne souhaitez pas désabonner manuellement tous les abonnements, procédez comme suit:

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)
    };
  };

}

Ensuite, vous pouvez l'utiliser comme décorateur dans votre composant

@AutoUnsubscribe
export class YourComponent  {
}

mais vous devez toujours stocker les abonnements en tant que propriétés de composant . Et lorsque vous naviguez hors composant, la fonction AutoUnsubscribe est activée.

10
Anton Lee

Je ne suis pas convaincu de la nécessité de la fonctionnalité demandée, mais vous pouvez le faire en annulant toutes les demandes en suspens quand et où vous le souhaitez en enveloppant le service http du framework et en lui déléguant.

Cependant, lorsque nous mettons en œuvre ce service, un problème devient rapidement évident. D'une part, nous aimerions éviter de modifier le code existant, y compris le code tiers, qui exploite le client http angular stock. D'autre part, nous aimerions éviter l'héritage d'implémentation.

Pour obtenir le meilleur des deux mondes, nous pouvons mettre en œuvre le service Angular Http avec notre wrapper. Le code existant continuera à fonctionner sans changement (à condition que ledit code ne fasse rien de stupide comme utiliser http instanceof Http).

import {Http, Request, RequestOptions, RequestOptionsArgs, Response} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';



export default interface CancellationAwareHttpClient extends Http { }

export default class CancellationAwareHttpClient {
  constructor(private wrapped: Http) {
    const delegatedMethods: Array<keyof Http> = [
      'get', 'post', 'put', 'delete',
      'patch', 'head', 'options'
    ];
    for (const key of delegatedMethods) {
      this[key] = wrapped[key].bind(wrapped);
    }
  }

  cancelOutstandingRequests() {
    this.subscriptions.forEach(subscription => {
      subscription.unsubscribe();
    });
    this.subscriptions = [];
  }

  request(url: string | Request, options?: RequestOptionsArgs) {
    const subscription = this.wrapped.request(url, options);
    this.subscriptions.Push(subscription);
    return subscription;
  }

  subscriptions: Subscription[] = [];
}

Notez que les déclarations interface et class pour CancellationAwareHttpClient sont fusionnées. De cette manière, notre classe implémente Http en vertu de la clause interface de la déclaration extends.

Maintenant, nous allons fournir notre service

import {NgModule} from '@angular/core';
import {ConnectionBackend, RequestOptions} from '@angular/http';

import CancellationAwareHttpClient from 'app/services/cancellation-aware-http-client';

let cancellationAwareClient: CancellationAwareHttpClient;

const httpProvider = {
  provide: Http,
  deps: [ConnectionBackend, RequestOptions],
  useFactory: function (backend: ConnectionBackend, defaultOptions: RequestOptions) {
    if (!cancellationAwareClient) {
      const wrapped = new Http(backend, defaultOptions);
      cancellationAwareClient = new CancellationAwareHttpClient(wrappedHttp);
    }
    return cancellationAwareClient;
  }
};

@NgModule({
  providers: [
    // provide our service as `Http`, replacing the stock provider
    httpProvider,
    // provide the same instance of our service as `CancellationAwareHttpClient`
    // for those wanting access to `cancelOutstandingRequests`
    {...httpProvider, provide: CancellationAwareHttpClient}
  ]
}) export class SomeModule {}

Notez comment nous substituons le service fourni par la structure existante. Nous utilisons une usine pour créer notre instance et n’ajoutons pas de décorateurs pour DI à l’emballeur lui-même afin d’éviter un cycle dans l’injecteur.

2
Aluan Haddad

ngOnDestroy callback est généralement utilisé pour tout nettoyage personnalisé devant se produire lorsque l'instance est détruite.

où voulez-vous annuler votre demande?

peut-être que si vous voulez annuler vos demandes sur le navigateur fermé, il y a une idée créative ici

2
Vala Khosravi

Essaye ça :

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Rx';

export class Component implements OnInit, OnDestroy {
    private subscription: Subscription;
    ngOnInit() {
        this.subscription = this.route.params.subscribe();
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
}
2
Chandru

Vous pouvez créer un service HTTP personnalisé (à l'aide de HttpClient) qui gère une liste des demandes en attente. Chaque fois que vous envoyez un service http à ce service personnalisé au lieu de Http/HttpClient, placez maintenant les abonnements dans une liste et, au retour de la réponse, supprimez-les. En utilisant cela, vous aurez tous les abonnements incomplets dans une liste. 

Maintenant, dans le même service personnalisé, injectez le routeur dans le constructeur et abonnez-vous dessus pour obtenir les événements de changement de route. Maintenant, chaque fois que cette observable émet, tout ce que vous avez à faire est de vous désabonner de tous les abonnements présents dans la liste et d’en extraire tous les éléments.

Si vous avez besoin d'un extrait de code, mentionnez-le en commentaire.

1
Sumit Agarwal