Подтвердить что ты не робот

Как отменить/отменить подписку на все ожидающие HTTP-запросы angular 4+

Как отменить/прервать все ожидающие запросы HTTP angular 4 +.

Существует метод unsubscribe для отмены запросов HTTP, но как отменить все ожидающие запросы все сразу.

Особенно при изменении маршрута.

Есть одна вещь, которую я сделал

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

но как достичь этого глобально

Любые идеи?

4b9b3361

Ответ 1

Извлеките оператора takeUntil() из RxJS, чтобы глобально отбросить ваши подписки:

- RxJS 6+ (с использованием синтаксиса 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 & lt; 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();
   }
}

Вы можете отправлять событие, если хотите отменить подписку Subject, используя next() каждый раз, когда хотите завершить несколько потоков. Также рекомендуется отказаться от подписки на активные Observables, поскольку компонент уничтожен, чтобы избежать утечек памяти.

Стоит прочитать:

Ответ 2

Вы можете создать перехватчик для применения оператора takeUntil к каждому запросу. Затем при изменении маршрута вы отправите событие, которое отменит все ожидающие запросы.

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

Вспомогательный сервис.

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

}

Отслеживайте изменения маршрута где-то в вашем приложении (например, onInit в appComponent).

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

Ответ 3

Если вы не хотите вручную отменить подписку на все подписки, вы можете сделать это:

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

}

Затем вы можете использовать его в качестве декоратора в своем компоненте

@AutoUnsubscribe
export class YourComponent  {
}

но вам все равно нужно хранить подписки в качестве свойств компонента. И когда вы переходите от компонента, будет выполняться функция AutoUnsubscribe.

Ответ 4

ngOnDestroy Обратный вызов обычно используется для любой пользовательской очистки, которая должна произойти при уничтожении экземпляра.

где вы хотите отменить свой запрос?

возможно, если вы хотите отменить свои запросы в браузере, там есть творческая идея здесь

Ответ 5

Попробуйте следующее:

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

Ответ 6

Я не уверен в необходимости запрошенной функции, но вы можете это сделать, отменяя все невыполненные запросы всякий раз, когда и где захотите, обертывая службу http-инфраструктуры и делегируя ей.

Однако, когда мы приступаем к внедрению этой службы, проблема быстро становится очевидной. С одной стороны, мы хотели бы избежать изменения существующего кода, включая сторонний код, который использует клиентский Angular http-клиент. С другой стороны, мы хотели бы избежать наследования реализации.

Чтобы получить лучшее из обоих миров, мы можем реализовать сервис Angular Http с нашей оболочкой. Существующий код будет продолжать работать без изменений (если указанный код не делает ничего глупого, как использование 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[] = [];
}

Обратите внимание, что объявления interface и class для CancellationAwareHttpClient объединены. Таким образом, наш класс реализует Http в силу предложения interface declaration extends.

Теперь мы предоставим наш сервис

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 {}

Обратите внимание на то, как мы переопределяем существующую предоставляемую инфраструктуру. Мы используем factory для создания нашего экземпляра и не добавляем декораторов для DI к самой оболочке, чтобы избежать цикла в инжекторе.

Ответ 7

    //This is the example of cancelling the get request once you leave the TestComponent.

    import { Component, OnInit} from '@angular/core';

    @Component({
      selector: 'app-test',
      templateUrl: './test.component.html'
    })
    export class TestComponent implements OnInit {

      request: any;
someList: any;

      constructor( private _someService: SomeService) {

      }

    ngOnInit() {
        this.getList();
      }

      ngOnDestroy(){
        this.request.unsubscribe(); // To cancel the get request.
      }

      getList() {
        this.request= this._someService.getAll()
          .subscribe((response: any) => {
            this.someList= response;
          }, (error) => {
            console.log("Error fetching List", error);
          })
      }

    }

Ответ 8

Вы можете создать пользовательскую службу Http (используя HttpClient), которая поддерживает список ожидающих запросов. Всякий раз, когда вы запускаете HTTP-почту этой настраиваемой службой вместо Http/HttpClient, теперь подталкивайте подписки к списку и возвращайте ответную поп-версию этой подписки. Используя это, вы получите все незавершенные подписки в списке.

Теперь в той же пользовательской службе Inject маршрутизатор в конструкторе и подписаться на него, чтобы получить события изменения маршрута. Теперь, когда это наблюдаемое испускает, все, что вам нужно сделать, это отменить подписку на все подписки, присутствующие в списке, и вытащить все элементы из него.

Если вам нужен фрагмент кода, укажите в комментарии.