[angular] Http 메소드로 생성 된 Observable을 구독 취소해야합니까?

메모리 누수를 방지하기 위해 Angular 2 http 호출을 구독 취소해야합니까?

 fetchFilm(index) {
        var sub = this._http.get(`http://example.com`)
            .map(result => result.json())
            .map(json => {
                dispatch(this.receiveFilm(json));
            })
            .subscribe(e=>sub.unsubscribe());
            ...



답변

대답은 ‘아니요’입니다. Ng2그것을 스스로 청소합니다.

Angular의 Http XHR 백엔드 소스의 Http 서비스 소스 :

여기에 이미지 설명을 입력하십시오

complete()결과를 얻은 후 실행 방법을 확인하십시오 . 이는 실제로 완료시 구독을 취소 함을 의미합니다. 따라서 직접 할 필요는 없습니다.

다음은 유효성을 검사하는 테스트입니다.

  fetchFilms() {
    return (dispatch) => {
        dispatch(this.requestFilms());

        let observer = this._http.get(`${BASE_URL}`)
            .map(result => result.json())
            .map(json => {
                dispatch(this.receiveFilms(json.results));
                dispatch(this.receiveNumberOfFilms(json.count));
                console.log("2 isUnsubscribed",observer.isUnsubscribed);
                window.setTimeout(() => {
                  console.log("3 isUnsubscribed",observer.isUnsubscribed);
                },10);
            })
            .subscribe();
        console.log("1 isUnsubscribed",observer.isUnsubscribed);
    };
}

예상 한대로 결과를 얻고 관찰 가능한 연산자로 완료 한 후에는 항상 자동으로 구독이 취소 된 것을 알 수 있습니다. 이는 타임 아웃 (# 3)에 발생하므로 모든 작업이 완료되면 관찰 가능 상태를 확인할 수 있습니다.

그리고 결과

여기에 이미지 설명을 입력하십시오

따라서 Ng2자동 수신 거부 로 누출이 발생하지 않습니다 !

언급하기 좋음 : 이것은 Observable로 분류 finite되는데, infinite Observable이는 click예를 들어 DOM 리스너 처럼 무한한 데이터 스트림이 방출 될 수 있습니다 .

감사합니다. @rubyboy


답변

사람들은 무엇에 대해 이야기하고 있습니까 !!!

확인 가능하므로 구독을 취소해야하는 두 가지 이유가 있습니다. 중요한 두 번째 이유에 대해 아무도 많이 이야기하지 않는 것 같습니다!

1) 자원을 정리하십시오. 다른 사람들이 말했듯이 이것은 HTTP 옵저버 블에게는 무시할만한 문제입니다. 그냥 정리해

2) subscribe핸들러가 실행되지 않도록하십시오 .

(HTTP의 경우 실제로 브라우저에서 요청을 취소하므로 응답을 읽는 데 시간을 낭비하지 않지만 실제로는 아래 주요 요점을 제외하고는 아닙니다.)

숫자 2의 관련성은 구독 처리기의 기능에 따라 다릅니다.

귀하의 경우 subscribe()핸들러 함수가 호출 어떤이 닫혀있는 경우 바람직하지 않은 또는 배치되어 부작용의 종류를 가지고 당신은 탈퇴 (또는 조건부 논리를 추가) 실행되는 것을 방지하기 위해해야합니다.

몇 가지 경우를 고려하십시오.

1) 로그인 양식. 사용자 이름과 비밀번호를 입력하고 ‘로그인’을 클릭하십시오. 서버 속도가 느리고 Esc를 눌러 대화 상자를 닫으려면 어떻게해야합니까? 로그인하지 않았다고 가정 할 수도 있지만 탈출을 누른 후에 http 요청이 반환되면 거기에있는 모든 논리를 계속 실행합니다. 이로 인해 계정 페이지로 리디렉션되거나 원치 않는 로그인 쿠키 또는 토큰 변수가 설정 될 수 있습니다. 이것은 아마도 사용자가 기대 한 것이 아닐 것입니다.

2) ‘이메일 보내기’양식.

는 IF subscribe‘sendEmail’에 대한 핸들러가 트리거 유사한 무언가를 당신이 예외 또는 원치 않는 동작을 얻을 수 있습니다 배치 된 액세스 아무것도 다른 페이지 또는 시도로 전송, 애니메이션 ‘이메일이 전송됩니다’.

또한 unsubscribe()‘취소’를 의미 하지 않도록주의하십시오 . HTTP 메시지가 비행 unsubscribe()중이면 HTTP 요청이 이미 서버에 도달 한 경우 HTTP 요청을 취소하지 않습니다. 답장 만 취소됩니다. 그리고 아마도 이메일이 전송 될 것입니다.

UI 구성 요소 내에서 직접 전자 메일을 보내도록 구독을 만들면 처리를 취소 할 수 있지만 UI가 아닌 중앙 집중식 서비스에서 전자 메일을 보내는 경우에는 그럴 필요가 없습니다.

3) 파괴 / 폐쇄 된 각도 성분. 에 아직 실행중인 http 옵저버 블은에서 구독을 취소하지 않으면 논리를 완료하고 실행합니다 onDestroy(). 결과가 사소한 지 여부는 구독 처리기에서 수행하는 작업에 따라 다릅니다. 더 이상 존재하지 않는 것을 업데이트하려고하면 오류가 발생할 수 있습니다.

구성 요소가 폐기 된 경우 원하는 작업이있을 수도 있고 그렇지 않은 경우도 있습니다. 예를 들어 보낸 이메일에 대해 ‘swoosh’소리가납니다. 구성 요소가 닫혀 있어도이 기능을 원할 수도 있지만 구성 요소에서 애니메이션을 실행하려고하면 실패합니다. 이 경우 subscribe 내부의 일부 조건부 논리가 해결책이 될 것입니다. http 관찰 가능을 구독 취소하지 않으려 고합니다.

따라서 실제 질문에 대한 답으로 메모리 누수를 피하기 위해 할 필요가 없습니다. 그러나 예외를 발생 시키거나 응용 프로그램 상태를 손상시킬 수있는 코드를 실행하여 원하지 않는 부작용이 발생하지 않도록하려면 종종 수행해야합니다.

팁 : 고급 부울 경우 유용한 부울 속성 이 Subscription포함되어 있습니다 closed. HTTP의 경우 완료시 설정됩니다. Angular에서는 일부 상황에서 핸들러 가 확인할 수 있는 _isDestroyed속성 을 설정하는 것이 유용 ngDestroy할 수 있습니다 subscribe.

팁 2 : 여러 구독을 처리하는 경우 임시 new Subscription()개체와 add(...)다른 구독을 만들 수 있습니다. 따라서 기본 구독을 구독 취소하면 추가 된 모든 구독도 구독 취소됩니다.


답변

호출 unsubscribe방법은이 방법은 호출 이후 진행중인 HTTP 요청을 취소하는 대신이다 abort부하 및 오류 이벤트에 대한 기본 XHR 객체 및 제거 청취자 하나를 :

// From the XHRConnection class
return () => {
  _xhr.removeEventListener('load', onLoad);
  _xhr.removeEventListener('error', onError);
  _xhr.abort();
};

즉, unsubscribe청취자를 제거합니다 … 그래서 좋은 아이디어 일 수는 있지만 단일 요청에 필요하다고 생각하지 않습니다. 😉

티에리가 당신을 도울 수 있기를 바랍니다.


답변

수신 거부는 A는 MUST 당신이 원하는 경우 결정 모든 네트워크 속도에서 동작을.

컴포넌트 A가 탭에 렌더링되었다고 가정 하십시오. 버튼을 클릭하여 ‘GET’요청을 보냅니다. 응답이 되돌아 오려면 200ms가 걸립니다. 따라서 기계가 사용자보다 빠르며 탭이 닫히고 구성 요소 A가 파괴되기 전에 http 응답이 처리되어 완료된다는 것을 알고 언제든지 탭을 닫는 것이 안전합니다.

매우 느린 네트워크에서는 어떻습니까? 버튼을 클릭하면 ‘GET’요청이 응답을받는 데 10 초가 걸리지 만 탭을 닫기로 결정하기까지 5 초가 걸립니다. 그러면 나중에 가비지 수집되는 구성 요소 A가 손상됩니다. 잠깐만! 구독을 취소하지 않았습니다. 이제 5 초 후에 응답이 다시 표시되고 삭제 된 구성 요소의 로직이 실행됩니다. 이 실행은 현재 고려 out-of-context되어 매우 낮은 성능을 포함하여 많은 것을 초래할 수 있습니다.

따라서 takeUntil()구성 요소가 손상 될 때 http 호출 을 사용 하고 구독을 취소 하는 것이 가장 좋습니다 .

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

interface User {
  id: string;
  name: string;
  age: number;
}

@Component({
  selector: 'app-foobar',
  templateUrl: './foobar.component.html',
  styleUrls: ['./foobar.component.scss'],
})
export class FoobarComponent implements OnInit, OnDestroy {
  private user: User = null;
  private destroy$ = new Subject();

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.http
      .get<User>('api/user/id')
      .pipe(takeUntil(this.destroy$))
      .subscribe(user => {
        this.user = user;
      });
  }

  ngOnDestroy(): void {
    this.destroy$.next();  // trigger the unsubscribe
    this.destroy$.complete(); // finalize & clean up the subject stream
  }
}


답변

또한 새로운 HttpClient 모듈에서도 동일한 동작이 유지됩니다.
꾸러미 /common/http/src/jsonp.ts


답변

자동으로 완료되는 관찰 가능 항목 (예 : Http, 호출)을 구독 취소해서는 안됩니다. 그러나와 같은 무한 관측 가능 항목을 구독 취소해야합니다 Observable.timer().


답변

테스트 후 잠시 동안 HttpClient의 문서와 소스 코드를 읽으십시오.

HttpClient: https://github.com/angular/angular/blob/master/packages/common/http/src/client.ts

HttpXhrBackend : https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.ts

HttpClientModule: https://indepth.dev/exploring-the-httpclientmodule-in-angular/

앵귤러 대학교 : https://blog.angular-university.io/angular-http/

이 특정 유형의 Observable은 단일 값 스트림입니다. HTTP 요청이 성공하면이 Observable은 하나의 값만 방출 한 다음 완료됩니다.

그리고 “do i NEED”의 전체 이슈에 대한 답변은 구독을 취소합니까?

때에 따라 다르지.
HTTP 호출 메모리 누출은 문제가되지 않습니다. 문제는 콜백 함수의 논리입니다.

예 : 라우팅 또는 로그인.

전화가 로그인 전화 인 경우 “구독 취소”할 필요는 없지만 사용자가 페이지를 떠날 경우 사용자가없는 경우 응답을 올바르게 처리해야합니다.


this.authorisationService
      .authorize(data.username, data.password)
      .subscribe((res: HttpResponse<object>) => {
          this.handleLoginResponse(res);
        },
        (error: HttpErrorResponse) => {
          this.messageService.error('Authentication failed');
        },
        () => {
          this.messageService.info('Login has completed');
        })

성가신 것에서 위험한 것까지

이제 네트워크가 평소보다 느리고 전화가 5 초 이상 걸리고 사용자가 로그인보기를 종료하고 “지원보기”로갑니다.

구성 요소가 활성 상태가 아닌 구독 일 수 있습니다. 응답이있는 경우, handleResponse () 구현에 따라 사용자가 갑자기 다시 라우팅됩니다.

이것은 아닙니다 좋지 .

또한 사용자가 아직 로그인하지 않았다고 믿고 PC를 떠났다고 상상해보십시오. 그러나 논리는 사용자를 로그인하여 보안 문제가 있습니다.

탈퇴하지 않고 무엇을 할 수 있습니까?

보기의 현재 상태에 따라 전화를 겁니다.

  public isActive = false;
  public ngOnInit(): void {
    this.isActive = true;
  }

  public ngOnDestroy(): void {
    this.isActive = false;
  }

.pipe(takeWhile(value => this.isActive))보기가 활성화 된 경우에만 응답이 처리되는지 확인하는 사용자 입니다.


this.authorisationService
      .authorize(data.username, data.password).pipe(takeWhile(value => this.isActive))
      .subscribe((res: HttpResponse<object>) => {
          this.handleLoginResponse(res);
        },
        (error: HttpErrorResponse) => {
          this.messageService.error('Authentication failed');
        },
        () => {
          this.messageService.info('Login has completed');
        })

그러나 구독이 메모리 누수를 일으키지 않는지 어떻게 알 수 있습니까?

“teardownLogic”이 적용되면 로그 할 수 있습니다.

서브 크립 션이 비어 있거나 구독 취소되면 서브 스크립 션의 teardownLogic이 호출됩니다.


this.authorisationService
      .authorize(data.username, data.password).pipe(takeWhile(value => this.isActive))
      .subscribe((res: HttpResponse<object>) => {
          this.handleLoginResponse(res);
        },
        (error: HttpErrorResponse) => {
          this.messageService.error('Authentication failed');
        },
        () => {
          this.messageService.info('Login has completed');
    }).add(() => {
        // this is the teardown function
        // will be called in the end
      this.messageService.info('Teardown');
    });

구독을 취소 할 필요가 없습니다. 논리에 문제가 있으면 구독에 문제를 일으킬 수 있는지 알아야합니다. 그리고 그들을 돌봐. 대부분의 경우 문제는 아니지만 자동화와 같은 중요한 작업에서는 특히 “구독 취소”또는 파이프 또는 조건부 콜백 함수와 같은 다른 논리를 사용하여 예기치 않은 동작을 처리해야합니다.

왜 항상 구독을 취소하지 않습니까?

풋 또는 포스트 요청을한다고 상상해보십시오. 서버는 메시지를 수신하지만 응답에는 시간이 걸립니다. 구독을 취소하면 게시물을 취소하거나 게시하지 않습니다. 그러나 구독을 취소하면 대화 나 토스트 / 메시지 등을 통해 응답을 처리하거나 사용자에게 알릴 기회가 없습니다.

Wich는 사용자가 풋 / 포스트 요청이 완료되지 않았다고 믿게합니다.

따라서 다릅니다. 이러한 문제를 처리하는 방법은 디자인 결정입니다.