특정 부작용에 대한 새 구독을 언제 작성해야합니까?


10

지난주에 RxJS 질문에 답변 했는데 다른 커뮤니티 멤버와 "모든 특정 부작용에 대해 구독을 작성해야합니까? 아니면 일반적으로 구독을 최소화해야합니까?" 완전한 반응 형 응용 프로그램 접근 방식 또는 서로 전환하는 시점에서 사용할 방법을 알고 싶습니다. 이것은 저와 다른 사람들이 불쾌한 토론을 피하는 데 도움이 될 것입니다.

설치 정보

  • 모든 예제는 TypeScript에 있습니다.
  • 질문에 더 초점을 맞추려면 구독에 수명주기 / 생성자를 사용하지 않고 프레임 워크를 관련이 없습니다.
    • 상상해보십시오. 구독은 생성자 / 라이프 사이클 초기화에 추가됩니다.
    • 상상 : 구독 취소는 수명주기에서 완료됩니다.

부작용이란 무엇입니까 (각도 샘플)

  • 업데이트 / UI에 입력 (예 value$ | async)
  • 구성 요소의 출력 / 업스트림 (예 @Output event = event$)
  • 서로 다른 계층에서 서로 다른 서비스 간 상호 작용

예시적인 사용 사례 :

  • 두 가지 기능 : foo: () => void; bar: (arg: any) => void
  • 두 가지 관측소 : http$: Observable<any>; click$: Observable<void>
  • foohttp$방출 후 호출 되며 값이 필요하지 않습니다.
  • barclick$방출 후 호출 되지만 현재 값이 필요합니다.http$

사례 : 모든 특정 부작용에 대한 구독 생성

const foo$ = http$.pipe(
  mapTo(void 0)
);

const bar$ = http$.pipe(
  switchMap(httpValue => click$.pipe(
    mapTo(httpValue)
  )
);

foo$.subscribe(foo);
bar$.subscribe(bar);

사례 : 일반적으로 구독 최소화

http$.pipe(
  tap(() => foo()),
  switchMap(httpValue => click$.pipe(
    mapTo(httpValue )
  )
).subscribe(bar);

간단히 말해서 내 자신의 의견

구독자가 Rx 환경을 더 복잡하게 만든다는 사실을 이해할 수 있습니다. 가입자가 파이프에 영향을 미치거나 예를 들어 관찰 할 수 있는지 여부를 고려해야하기 때문입니다. 그러나 코드를 더 많이 분리할수록 (포커스가 많을수록 발생하는시기) 나중에 코드를 유지 관리 (테스트, 디버그, 업데이트)하기가 쉬워집니다. 이를 염두에두고 항상 관찰 가능한 단일 소스와 코드의 부작용에 대한 단일 구독을 만듭니다. 두 개 이상의 부작용이 정확히 동일한 소스 관찰 가능 항목에 의해 트리거되는 경우 관찰 가능 항목을 공유하고 각 부작용을 개별적으로 구독합니다. 수명주기가 다를 수 있기 때문입니다.

답변:


6

RxJS는 비동기 작업을 관리하는 데 유용한 리소스이며 가능한 경우 코드 (구독 수 감소 포함)를 단순화하는 데 사용해야합니다. 마찬가지로 RxJS가 애플리케이션에서 전체 구독 수를 줄일 수있는 솔루션을 제공하는 경우 옵저버 블 뒤에 자동으로 해당 옵저버 블에 대한 구독이 없어야합니다.

그러나 '필수'가 아닌 구독을 작성하는 것이 유리한 상황이 있습니다.

예외 예-단일 템플릿에서 관찰 가능 항목 재사용

첫 번째 예를 보면 :

// Component:

this.value$ = this.store$.pipe(select(selectValue));

// Template:

<div>{{value$ | async}}</div>

value $가 템플릿에서 한 번만 사용되는 경우 비동기 파이프와 코드 절약 및 자동 가입 취소에 대한 이점을 활용합니다. 그러나이 답변 에 따라 템플릿의 동일한 비동기 변수에 대한 여러 참조는 피해야합니다.

// It works, but don't do this...

<ul *ngIf="value$ | async">
    <li *ngFor="let val of value$ | async">{{val}}</li>
</ul>

이 상황에서 대신 별도의 구독을 작성하고이를 사용하여 컴포넌트에서 비동기가 아닌 변수를 업데이트합니다.

// Component

valueSub: Subscription;
value: number[];

ngOnInit() {
    this.valueSub = this.store$.pipe(select(selectValue)).subscribe(response => this.value = response);
}

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

// Template

<ul *ngIf="value">
    <li *ngFor="let val of value">{{val}}</li>
</ul>

기술적으로는 없이도 동일한 결과를 얻을 수 valueSub있지만 응용 프로그램의 요구 사항은 이것이 올바른 선택임을 의미합니다.

구독 여부를 결정하기 전에 관찰 가능 항목의 역할 및 수명 고려

둘 이상의 관측 가능 항목을 함께 사용할 때만 사용하는 경우 적절한 RxJS 연산자를 사용하여 단일 관측 값으로 결합해야합니다.

마찬가지로, first () 를 사용하여 Observable의 첫 번째 방출을 제외한 모든 것을 걸러내는 경우, 지속적인 역할을 수행하는 Observable보다 코드를 경제적으로 사용하고 '추가'구독을 피해야 할 더 큰 이유가 있다고 생각합니다. 세션.

개별 옵저버 블 중 하나가 다른 옵저버 블과 독립적으로 유용한 경우 별도의 구독 (들)의 유연성과 명확성을 고려할 가치가 있습니다. 그러나 초기 진술에 따라 명확한 이유가없는 한 모든 관찰 가능 항목에 대해 구독을 자동으로 생성해서는 안됩니다.

수신 거부 관련 :

추가 구독 대한 요점 은 더 많은 구독 취소 가 필요하다는 것입니다. 말씀 드린대로, 필요한 모든 탈퇴가 Destroy에 적용되었다고 가정하고 싶지만 실제 생활이 항상 그렇게 원활하게 진행되는 것은 아닙니다! 다시, RxJS는 이 프로세스를 간소화 하는 유용한 도구 (예 : first () )를 제공하여 코드를 단순화하고 메모리 누수 가능성을 줄입니다. 이 기사 에서는 유용한 추가 정보와 예제를 제공합니다.

개인 취향 / 상세와 간결함 :

자신의 취향을 고려하십시오. 코드의 세부 정보에 대한 일반적인 토론을하고 싶지는 않지만 너무 많은 '노이즈'와 코드를 지나치게 암호로 만드는 것 사이의 적절한 균형을 찾는 것이 목표입니다. 이것은 가치가있을 수 있습니다 .


먼저 자세한 답변에 감사드립니다! # 1과 관련하여 비동기 관점은 구독 / 부작용이며 지시문 안에 가려져 있습니다. # 2와 관련하여 몇 가지 코드 샘플을 추가 할 수 있습니까, 정확히 말한 내용을 알 수는 없습니다. 구독 취소와 관련하여 : ngOnDestroy 이외의 다른 곳에서 구독을 구독 취소해야 할 때까지 본 적이 없었습니다. First ()는 기본적으로 구독 취소를 실제로 관리하지 않습니다. 구성 요소가 손상되었지만 0 emits = subscription open입니다.
Jonathan Stellwag

1
포인트 2는 구독을 설정할 때마다 모든 관찰 가능 항목을 자동으로 따르는 것이 아니라 구독 설정 여부를 결정할 때 각 관찰 가능 역할을 고려하는 것입니다. 이 시점에서 나는 medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87살펴볼 것을 제안합니다 . "너무 많은 구독 객체를 유지하는 것은 구독을 필수적으로 관리하고 있으며 이점을 취하지 않는 신호입니다. "Rx의 힘."
매트 손더스

1
감사합니다 @JonathanStellwag. info RE 콜백에 대해서도 감사합니다. 앱에서이를 방지하기 위해 모든 구독 (예 : first ()가 사용되는 경우에도)에서 명시 적으로 구독을 취소 하시겠습니까?
매트 손더스

1
네 저도 그렇습니다. 현재 프로젝트에서는 항상 구독을 취소하여 모든 노드의 약 30 %를 최소화했습니다.
Jonathan Stellwag

2
구독 취소에 대한 선호는 takeUntil에서 호출 된 함수와 함께 사용됩니다 ngOnDestroy. 파이프에 이것을 추가하는 하나의 라이너입니다 takeUntil(componentDestroyed(this)). stackoverflow.com/a/60223749/5367916
커트 해밀턴

2

구독 최적화가 최종 게임이라면 논리적 인 극단으로 가서 다음과 같은 일반적인 패턴을 따르십시오.

 const obs1$ = src1$.pipe(tap(effect1))
 const obs2$ = src2$pipe(tap(effect2))
 merge(obs1$, obs2$).subscribe()

탭에서 독점적으로 부작용을 실행하고 병합을 사용하여 활성화하면 구독이 하나만 있음을 의미합니다.

이것을하지 않는 한 가지 이유는 RxJS를 유용하게 만드는 많은 것들을 중립화하고 있기 때문입니다. 관찰 가능한 스트림을 작성하고 필요에 따라 스트림을 구독 / 구독 해제하는 기능입니다.

나는 관찰 가능 항목이 논리적으로 구성되어 있고 구독 감소라는 이름으로 오염되거나 혼동되어서는 안된다고 주장합니다. foo 효과를 논리적으로 bar 효과와 결합해야합니까? 하나는 다른 하나를 필요로합니까? http $가 발생할 때 foo 트리거를 원하지 않을 것입니까? 관련없는 기능간에 불필요한 연결을 생성하고 있습니까? 이것들은 모두 하나의 스트림에 넣지 않는 이유입니다.

이것은 여러 구독 IMO로 관리하기 쉬운 오류 처리를 고려하지 않아도됩니다.


답변 주셔서 감사합니다. 답변이 하나만 허용되어 죄송합니다. 귀하의 답변은 @Matt Saunders가 작성한 답변과 동일합니다. 또 다른 관점입니다. Matt의 노력 때문에 나는 그에게 동의를 주었다. 당신이 나를 용서할 수 있기를 바랍니다 :)
Jonathan Stellwag
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.