programing

Angular 4+에서 보류 중인 모든 HTTP 요청을 취소/구독 해제하는 방법

telebox 2023. 8. 25. 23:30
반응형

Angular 4+에서 보류 중인 모든 HTTP 요청을 취소/구독 해제하는 방법

Angular 4+에서 보류 중인 모든 HTTP 요청을 취소/중지하는 방법.

이 있습니다.unsubscribeHTTP 요청을 취소하는 방법이지만 보류 중인 모든 요청을 한 번에 취소하는 방법입니다.

특히 경로 변경 중에.

제가 한 일이 있습니다.

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

하지만 전 세계적으로 이를 달성하는 방법.

아이디어가 있습니까?

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 < 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()스트림 묶음을 완료할 때마다.또한 메모리 누수를 방지하기 위해 구성 요소가 파괴될 때 활성 관찰 항목에 대한 구독을 취소하는 것이 좋습니다.

읽을 가치가 있습니다.

적용할 인터셉터를 생성할 수 있습니다.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()
  }

}

경로 변경 사항에 대한 후크(예: appComponent의 Init).

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

마지막으로 인터셉트를 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 { }

모든 구독을 수동으로 취소하지 않으려면 다음을 수행할 수 있습니다.

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

그러나 헤드라인 등록을 구성 요소 속성으로 저장해야 합니다.그리고 구성 요소를 벗어나 탐색하면 자동 구독 취소 기능이 발생합니다.

요청된 기능의 필요성을 확신할 수 없지만, 프레임워크의 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병합됩니다.이런 식으로 우리 은 다음과 같이 구현합니다. Httpinterface신고의.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 {}

기존 프레임워크가 제공하는 서비스를 재정의하는 방법에 주목합니다.우리는 공장을 사용하여 인스턴스를 만들고 인젝터의 사이클을 방지하기 위해 래퍼 자체에 DI용 데코레이터를 추가하지 않습니다.

ngOnDestroy콜백은 일반적으로 인스턴스가 삭제될 때 수행해야 하는 모든 사용자 지정 정리에 사용됩니다.

어디에서 당신의 요청을 취소하시겠습니까?

아마도 당신이 브라우저 클로즈에서 당신의 요청을 취소하고 싶다면 여기에 창의적인 아이디어가 있습니다.

사용:

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

    }

@Bladi에 무언가를 추가하여 거의 완벽한 대답을 합니다.

사실 HttpCancelService 스택은 완벽하지만 문제는 어디에 호출되는지입니다.하위 경로가 있는 경우 탐색 끝에서 이 번호를 호출하면 문제가 발생할 수 있습니다.

그래서 저는 HttpCancelService가 파괴되면 호출하는 추상 컨테이너 구성요소를 만들었습니다.그래야 내가 Http Canceling 요청을 더 미세한 입자로 자르고 싶을 때 관리할 수 있습니다.

import { Component, OnDestroy, OnInit } from '@angular/core';
import { HttpCancelService } from '../../services/http-cancel-service.service';

@Component({
  selector: 'some-abstract-container',
  template: `
    ABSTRACT COMPONENT
  `,
  styleUrls: ['./abstract-container.component.scss']
})
export class AbstractContainerComponent implements OnInit, OnDestroy {
  constructor(protected readonly httpCancelService: HttpCancelService) {}

  ngOnInit() {}

  ngOnDestroy(): void {
    this.httpCancelService.cancelPendingRequests();
  }
}


추상적인 구성요소를 확장하는 구체적인 구성요소가 있습니다.

import { Component, OnInit } from '@angular/core';
import { AbstractContainerComponent } from '../../../shared/components/abstract-container/abstract-container.component';
import { HttpCancelService } from '../../../shared/services/http-cancel-service.service';

@Component({
  selector: 'some-concrete-container',
  templateUrl: '.some-concrete-container.component.html',
  styleUrls: ['./some-concrete-container.component.scss']
})
export class SomeConcreteContainerComponent extends AbstractContainerComponent implements OnInit {
  constructor(protected readonly httpCancelService: HttpCancelService) {
    super(httpCancelService);
  }

  ngOnInit() {}
}

경로 변경 수준의 요청은 세분성이 떨어지기 때문에 취소하는 것은 좋은 생각이 아니라고 생각합니다.

예를 들어, 한 구성 요소에 대한 요청을 취소하고 다른 구성 요소에 대한 요청이 손상되지 않도록 취소할 수 있습니다.가장 중요한 것은, 배경 요청은 어떻습니까?일부 요청이 임의로 취소된 이유를 디버그하는 것은 매우 중요합니다.

으로 취소하는 것은 좋은 생각입니다.get경로 변경에 관계없이 구성 요소가 파괴될 요청입니다.


파괴 시 관찰 가능한 항목에서 등록 취소

당신의 삶을 쉽게 만들고 싶다면 파괴될 때까지 사용하세요.구성 요소가 파괴될 때 자동으로 모든 관찰 항목의 구독을 취소합니다.ngOnDestroy) (만 아니라 . . . . . HttpRequests도 마찬가지입니다.observables에서 구독 취소됨)

import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
     
@UntilDestroy()
@Component({})
export class InboxComponent {
  ngOnInit() {
    interval(1000)
      .pipe(untilDestroyed(this))
      .subscribe();
  }
}

보류 중인 요청 목록을 유지 관리하는 사용자 정의 Http 서비스를 만들 수 있습니다(HttpClient 사용).Http/HttpClient 대신 이 사용자 지정 서비스를 실행할 때마다 이제 구독을 목록에 밀어넣고 해당 구독을 내보내는 응답 팝업을 반환합니다.이 옵션을 사용하면 모든 불완전한 구독이 목록에 표시됩니다.

이제 동일한 사용자 지정 서비스에서 생성자에 라우터를 주입하고 루트 변경 이벤트를 가져오려면 라우터를 구독합니다.이제 이 관찰 가능한 항목이 표시될 때마다 목록에 있는 모든 구독을 취소하고 목록에서 모든 요소를 팝업하기만 하면 됩니다.

코드 스니펫이 필요하면 코멘트에 언급하십시오.

다음은 매우 간단하고 테스트된 작동 예입니다.

import { Component, ViewChild, ElementRef } from "@angular/core";
import { DataService } from "../services/data.service";

@Component({
  selector: "app-home",
  templateUrl: "home.page.html",
  styleUrls: ["home.page.scss"],
})
export class HomePage {
  @ViewChild("image") image: ElementRef;
  loading = false;
  subscriptions = [];
  constructor(private dataService: DataService) {}

  start() {
    this.loading = true;
    this.image.nativeElement.classList.add("animate");
    const subscription = this.dataService
      .paymentRequest()

      .subscribe(
        (data) => {
          this.image.nativeElement.classList.remove("animate");
          this.loading = false;
          console.log(data);
        },
        (error) => this.start()
      );
    this.subscriptions.push(subscription);
  }

  stop() {
    this.loading = false;
    this.image.nativeElement.classList.remove("animate");
    this.subscriptions.forEach((subscription) => {
      subscription.unsubscribe();
    });
    this.subscriptions = [];
    // This completes the subject properlly.
  }
}

언급URL : https://stackoverflow.com/questions/46068908/how-to-cancel-unsubscribe-all-pending-http-requests-in-angular-4

반응형