[4+1가지 방법] 구독을 취소하는 방법. 각도상.😎


소개하다.
본고에서 우리는 구독 취소의 가장 좋은 실천(Observables라고도 부른다)과 코드가 깨끗하고 구조가 양호하며 메모리 유출을 피하는 방법을 볼 수 있다.
간단히 말해서
  • 각도 내장 파이프async
  • RxJS 운영자(예: takeUntil
  • 구독한 사용자 정의 그룹
  • npm팩SubSink
  • npm팩@ngneat/until-destroy
    문제.🤔
    만약 당신이 Angular 측의 경험을 가지고 있다면, 당신은 이미 RxJS 가 가장 강력한 소프트웨어 패키지 중의 하나라는 것을 알고 있습니다.그것은 비동기적이고 이벤트 기반 코드를 관찰 가능한 개념으로 처리하고 처리한다.더욱 구체적으로 말하면 Observable은 실체로 시간에 따라 여러 개의 데이터 값을 보낸다.

    It sounds cool, right? Yes, it is cool and powerful, but you already know that!

    What's the problem with Observables then? Memory Leak!


    메모리 유출 문제를 하나의 예로 설명하기 위해서 제가 상세하게 설명해 드리겠습니다.다음에 우리는 3개의 관측 값을 초기화하여 1초마다 하나의 값을 보내고 각 관측 값에 구독을 창설한다.
    @Component(/* ... */)
    export class ProblematicExampleComponent implements OnInit {
      constructor() {}
    
      ngOnInit() {
        interval(1000).subscribe((value) => {
          console.log('sub1', value);
        });
        interval(1000).subscribe((value) => {
          console.log('sub2', value);
        });
        interval(1000).subscribe((value) => {
          console.log('sub3', value);
        });
      }
    }
    
    우리의 코드는 유효한 것 같다.그러나 만약 우리가 이 구성 요소를 없애면 (예를 들어 이 구성 요소를 포함하지 않는 다른 경로를 탐색하면) 무슨 일이 일어날까요?이 값들은 계속 기록될 것입니다!
    더 심각한 상황은 우리가 이전 노선으로 돌아가면 값이 두 번 인쇄된다는 것이다.비록 우리가 구독을 정리하지 않는 상황에서 점점 더 많은 구독을 만들었지만, 이것은 메모리 유출의 전형적인 예이다.

    1. 파이프async우리가 알고 있는 바와 같이 Angular는 우리에게 많은 내장 기능을 제공하기 때문에 우리는 제3자 라이브러리를 선택해서 이러한 기능을 걱정할 필요가 없다(이것이 우리가 좋아하는 이유이다)❤️ 필경 모서리가 분명하잖아, 그렇지?async 파이프는 바로 이런 유용한 기능이다.
    보기official documentation:

    The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. When a new value is emitted, the async pipe marks the component to be checked for changes. When the component gets destroyed, the async pipe unsubscribes automatically to avoid potential memory leaks.


    예:
    // async-example.component.ts
    
    import { Component } from '@angular/core';
    import { interval } from 'rxjs';
    import { tap } from 'rxjs/operators';
    import { Logger } from '../utils/logger';
    
    @Component(/* ... */)
    export class AsyncExampleComponent {
      private logger = new Logger(AsyncExampleComponent.name);
    
      obs1$ = interval(1000).pipe(
        tap((value) => {
          this.logger.log('sub1', value);
        })
      );
      obs2$ = interval(1000).pipe(
        tap((value) => {
          this.logger.log('sub2', value);
        })
      );
      obs3$ = interval(1000).pipe(
        tap((value) => {
          this.logger.log('sub3', value);
        })
      );
    
      constructor() {}
    }
    
    <!-- async-example.component.html -->
    
    <p>Observable 1 value: {{obs1$ | async}}</p>
    <p>Observable 2 value: {{obs2$ | async}}</p>
    <p>Observable 3 value: {{obs3$ | async}}</p>
    
    <!-- Pro Tip -->
    <ng-container *ngIf="obs1$ | async as val1">
      <p>Observable 1 value: {{val1}}</p>
    </ng-container>
    
    위의 예에서 보듯이 구성 요소를 만드는 과정에서 RxJS의 interval 조작부호를 사용하여 3개의 관측 값을 초기화하였는데, 그것들은 1초마다 하나의 값을 낸다.
    동시에 우리는 이러한 관측 값이 async 파이프를 통해 템플릿으로 전송되는 것을 볼 수 있다.이것은 초기화하는 동안 자동으로 subscribe, 구성 요소가 소각되는 동안 자동으로 unsubscribe 된다는 것을 의미한다.이것은 매우 큰 장점을 구성한다. 왜냐하면 우리는 코드를 통해 스스로 완성할 필요가 없기 때문이다.

    2. RxJS 운영자
    다시 한 번 RxJS가 여기서 우리를 돕는다.그것은 구독을 취소하는 데 도움을 주는 많은 유용한 조작원들을 제공했다.
    먼저 다음과 같은 몇 가지 정의를 살펴보겠습니다.

  • 주제: ASubject는 관찰자 간에 실행 경로를 공유하는 특수한 유형의 관찰 대상입니다.너는 그것을 사람이 가득한 방에서 마이크를 향해 말하는 사람으로 상상할 수 있다.그들의 정보(주제)는 동시에 많은 (멀티캐스트)인(관찰자)에게 전달된다.이것은 멀티캐스트의 기초다.전형적인 관찰 결과는 일대일 대화와 비견할 만하다.

  • 간격: 관측 가능한 값의 조작부호를 되돌려줍니다. 이 관측 가능한 값은 제공된 시간 구조에 따라 순서대로 숫자를 보냅니다.

  • TakeTill: 관찰할 수 있는 발사 전에 발사하는 값을 제공하는 필터 조작부호.
  • 예:
    // take-until-example.component.ts
    
    import { Component, OnDestroy, OnInit } from '@angular/core';
    import { interval, Subject } from 'rxjs';
    import { takeUntil } from 'rxjs/operators';
    import { Logger } from '../utils/logger';
    
    @Component(/* ... */)
    export class TakeUntilExampleComponent implements OnInit, OnDestroy {
      private logger = new Logger(TakeUntilExampleComponent.name);
      private unsubscribe$ = new Subject<void>();
    
      constructor() {}
    
      ngOnInit() {
        interval(1000)
          .pipe(takeUntil(this.unsubscribe$))
          .subscribe((value) => {
            this.logger.log('sub1', value);
          });
        interval(1000)
          .pipe(takeUntil(this.unsubscribe$))
          .subscribe((value) => {
            this.logger.log('sub2', value);
          });
        interval(1000)
          .pipe(takeUntil(this.unsubscribe$))
          .subscribe((value) => {
            this.logger.log('sub3', value);
          });
      }
    
      ngOnDestroy() {
        this.unsubscribe$.next();
        this.unsubscribe$.complete();
      }
    }
    
    이제 위의 예를 자세히 살펴보겠습니다.
  • 우선, 우리는 새로운 Subject를 초기화했습니다. 이것은 어떠한 데이터 형식도 보내지 않습니다(void.
  • 그리고 우리는 interval 조작부호의 도움으로 3개의 관측 가능한 값을 만들었다.
  • 우리는 takeUntil 값을 필터할 때까지 파이프로 전달할 것이다.
  • 마지막이지만 가장 중요하지 않은 단계는 unsubscribe$ 기간에 촉발하는 것이다unsubscribe$.우리는 ngOnDestroy 방법으로 새로운 값 발사를 촉발하고 .next() 방법으로 모든 관찰자의 구독을 자동으로 취소합니다.
  • 비록 우리는 .complete() 연산자만 사용했지만, 또 다른 연산자가 우리를 도울 수 있다.예를 들어, 다음을 사용할 수 있습니다.

  • take: 완성되기 전에 주어진 수량의 값을 보냅니다.첫 발사에만 관심이 있을 때 사용할 수 있다takeUntil.사용자가 페이지에 들어갈 때 처음 클릭한 내용을 보고 싶거나, 클릭 이벤트를 구독하고 싶으면 첫 번째 클릭만 하면 된다.

  • takeWhile: 표현식이 false일 때까지 값을 보냅니다.선택할 수 있는inclusive 매개 변수가true로 설정되었을 때 사용할 수 있습니다. 술어가 전달되지 않은 첫 번째 항목을 내보냅니다.

  • 3. 사용자 정의 구독 배열
    또 다른 구독 취소 atake는 그것들을 하나의 그룹에 넣는 것이다.따라서, 우리는 모든 항목을 교체할 수 있으며, 구성 요소가 소각되는 동안 이 그룹의 모든 항목을 호출할 수 있다. Subscription 방법.
    예:
    // custom-array-example.component.ts
    
    import { Component, OnDestroy, OnInit } from '@angular/core';
    import { interval, Subscription } from 'rxjs';
    import { Logger } from '../utils/logger';
    
    @Component(/* ... */)
    export class CustomArrayExampleComponent implements OnInit, OnDestroy {
      private logger = new Logger(CustomArrayExampleComponent.name);
      private subs: Subscription[] = [];
    
      constructor() {}
    
      ngOnInit() {
        const sub1 = interval(1000).subscribe((value) => {
          this.logger.log('sub1', value);
        });
        this.subs.push(sub1);
    
        const sub2 = interval(1000).subscribe((value) => {
          this.logger.log('sub2', value);
        });
        this.subs.push(sub2);
    
        const sub3 = interval(1000).subscribe((value) => {
          this.logger.log('sub3', value);
        });
        this.subs.push(sub3);
      }
    
      ngOnDestroy() {
        this.subs.forEach((s) => s.unsubscribe());
      }
    }
    
    이런 방법은 어떠한 제3자 라이브러리도 없는 상황에서 여러 개의 구독을 잘 처리할 수 있다.그러나 세 가지 중요한 단점이 있다.
  • 구성 요소
  • 의 추가 변수를 초기화해야 합니다
  • 모든 새로운 .unsubscribe()에 대해 우리는 그것을 그룹에 추가해야 한다
  • 우리는 교체된 그룹을 잊을 수 없으며 Subscription에서 프로젝트의 구독을 취소할 수 없습니다

  • 4.ngOnDestroynpm 패키지
    이제는 일부 제3자 라이브러리를 볼 때가 되었다. 그들은 우리가 구독을 취소하는 것을 도울 수 있다.더욱 구체적으로 말하면 SubSink 라이브러리는 구성 요소에서 우아하게 구독을 취소하는 RxJS 구독 수신기를 구성한다.그것의 용법은 매우 간단해서 너는 아래에서 그것의 작용을 볼 수 있다.
    예:
    // subsink-example.component.ts
    
    import { Component, OnDestroy, OnInit } from '@angular/core';
    import { interval } from 'rxjs';
    import { SubSink } from 'subsink';
    import { Logger } from '../utils/logger';
    
    @Component(/* ... */)
    export class SubsinkExampleComponent implements OnInit, OnDestroy {
      private logger = new Logger(SubsinkExampleComponent.name);
      private subs = new SubSink();
    
      constructor() {}
    
      ngOnInit() {
        this.subs.sink = interval(1000).subscribe((value) => {
          this.logger.log('sub1', value);
        });
        this.subs.sink = interval(1000).subscribe((value) => {
          this.logger.log('sub2', value);
        });
        this.subs.sink = interval(1000).subscribe((value) => {
          this.logger.log('sub3', value);
        });
      }
    
      ngOnDestroy() {
        this.subs.unsubscribe();
      }
    }
    
    위의 예에서 우리는 subsink 변수를 subs류의 새로운 실례로 초기화할 것이다.두 번째 단계는 SubSink 속성을 사용하여setter로 구독을 수집합니다.마지막으로, 우리는 sink 방법으로 모든 구독을 취소합니다. 우리가 구성 요소 unsubscribe() 생명주기 이벤트에서 한 것처럼.
    보시다시피, 사용법은 매우 간단하고, 이전에 맞춤형 구독 그룹을 사용했던 방법과 유사합니다.

    5.OnDestroynpm 패키지

    👍 Personal Preference


    마지막으로 가장 중요하지 않은 것은 도서관@ngneat/until-destroy을 볼 것이다.
    앞의 방법과 유사하게, 우리는 원본 코드에서 매우 간단하게 사용한다.
    예:
    // until-destroy-example.component.ts
    
    import { Component, OnInit } from '@angular/core';
    import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
    import { interval } from 'rxjs';
    import { Logger } from '../utils/logger';
    
    @UntilDestroy()
    @Component(/* ... */)
    export class UntilDestroyExampleComponent implements OnInit {
      private logger = new Logger(UntilDestroyExampleComponent.name);
    
      constructor() {}
    
      ngOnInit() {
        interval(1000)
          .pipe(untilDestroyed(this))
          .subscribe((value) => {
            this.logger.log('sub1', value);
          });
        interval(1000)
          .pipe(untilDestroyed(this))
          .subscribe((value) => {
            this.logger.log('sub2', value);
          });
        interval(1000)
          .pipe(untilDestroyed(this))
          .subscribe((value) => {
            this.logger.log('sub3', value);
          });
      }
    }
    
    이 예에서 우리는 장식기를 사용했기 때문에 약간 다른 방법을 사용했다.우선, 우리는 구성 요소에 @ngneat/until-destroy 장식기를 추가한 다음에observable의 파이프에 @UntilDestroy() 조작부호를 전달합니다.
    비록 모든 사례가 서로 다른 용례에 적용되지만, 이것은 내가 가장 좋아하는 방법이며, 나는 프로젝트에서 자주 그것을 사용한다.개인적으로 저는 제3자 라이브러리를 설치하고 깨끗하고 읽기 쉬운 원본 코드를 얻는 것을 좋아합니다.

    결론✅
    만세!우리 끝까지 했어!🙌
    나는 네가 이 글을 좋아하고 가장 적합한 방식을 선택해서 너의 관찰을 취소함으로써 너의 응용 프로그램이 더욱 깨끗하고 메모리 유출 문제가 없도록 하기를 바란다.

    I would be more than happy to hear your personal preference or suggest other ways, leaving your comments down below!


    당신의 관점으로 이 문장을 지지해 주십시오❤️ 🦄 🔖 그것을 더욱 광범위한 관중에게 전파하도록 돕다.🙏
    또한 질문이 있으시면 언제든지 연락주시고 댓글이나 트위터 DMs를 남겨주세요.
    Stackblitz에서 최종 소스 코드를 찾을 수 있습니다.
    표지 사진은 Ali KazalUnsplash에서 찍었다.

    좋은 웹페이지 즐겨찾기