如何取消/取消订阅所有挂起的HTTP请求的角度4+

Sib*_*raj 30 rxjs typescript angular-http-interceptors angular

如何取消/中止所有挂起的HTTP请求的角度4+.

有一种unsubscribe方法可以取消HTTP请求,但是如何一次取消所有待处理的请求.

特别是路线变化时.

我做了一件事

ngOnDestroy() {
  this.subscription.unsubscribe();
}
Run Code Online (Sandbox Code Playgroud)

但如何在全球实现这一目标

有任何想法吗?

Ale*_*ues 49

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();
   }
}
Run Code Online (Sandbox Code Playgroud)

- 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();
   }
}
Run Code Online (Sandbox Code Playgroud)

你基本上可以发出你的退订事件Subject使用next()每次要完成一堆流.在组件被销毁时,取消订阅活动Observable也是一种好习惯,以避免内存泄漏.

值得阅读 :


Bla*_*ito 29

您可以创建一个拦截器以将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()))
  }
}
Run Code Online (Sandbox Code Playgroud)

帮手服务.

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

}
Run Code Online (Sandbox Code Playgroud)

路线上的钩子会在应用程序中发生变化(例如应用程序组件).

this.router.events.subscribe(event => {
  if (event instanceof ActivationEnd) {
    this.httpCancelService.cancelPendingRequests()
  }
})
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是最好的方法 (2认同)
  • 这看起来很棒,但是却忘记完成主题以关闭它 (2认同)
  • @Logus 我没有故意关闭它,因为该服务在应用程序存在的整个时间里都存在,并且关闭流无论如何都不会释放任何资源。如果该主题已完成,则您需要一遍又一遍地创建新主题。什么时候创建?谁来承担这个责任?它只会使代码更复杂,恐怕它不会增加任何价值。如果我错了,请随时纠正我。 (2认同)

Ant*_*Lee 10

如果您不想手动取消订阅所有订阅,则可以执行以下操作:

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

}
Run Code Online (Sandbox Code Playgroud)

然后,您可以将其用作组件中的装饰器

@AutoUnsubscribe
export class YourComponent  {
}
Run Code Online (Sandbox Code Playgroud)

但您仍需要将订阅存储为组件属性.当您导出组件时,将发生AutoUnsubscribe功能.


Alu*_*dad 6

我不相信需要所请求的功能,但您可以实现这一点,通过包装框架的 http 服务并委托给它,随时随地取消所有未完成的请求。

然而,当我们开始实施这项服务时,一个问题很快就会显现出来。一方面,我们希望避免更改现有代码,包括利用现有 Angular http 客户端的第三方代码。另一方面,我们希望避免实现继承。

为了两全其美,我们可以使用包装器实现AngularHttp服务。现有代码将继续工作而无需更改(前提是所述代码不会像 use 那样做任何愚蠢的事情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[] = [];
}
Run Code Online (Sandbox Code Playgroud)

请注意,合并了interfaceclass声明CancellationAwareHttpClient。通过这种方式,我们班器具 Http凭借的interface声明的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 {}
Run Code Online (Sandbox Code Playgroud)

请注意我们如何覆盖现有框架提供的服务。我们使用工厂来创建我们的实例,并且不会为 DI 添加任何装饰器到包装器本身,以避免注入器中的循环。


Val*_*avi 4

ngOnDestroy回调通常用于实例被销毁时需要进行的任何自定义清理。

您想在哪里取消您的请求?

也许如果你想取消浏览器关闭时的请求,这里有一个创意

  • 唯一可以放置在路由器插座上的组件。因为当路由器出口更改时,“ngOnDestroy()”被调用。 (2认同)