티스토리 뷰
[번역글] Angular에서 Rx.js의 Observable 관리하기
본 포스팅은 다음의 원문을 번역한 글입니다. 많은 의역이 포함되어 있을 수 있습니다.
원문: Manage your observable subscriptions in Angular with help of rx.js
서브스크립션(Subscription)을 위해 Observable
변수를 사용 할 때, 이 변수를 관리하는 것은 아주 중요합니다. Observable
은 영원히 동작할 수 있으므로 우리는 이 Observable
의 사용이 끝났을 때, 중지하는 것이 필요합니다. 만약 우리가 서브스크립션을 중단하지 않고 계속 유지한다면, 불필요한 메모리와 컴퓨팅 자원이 낭비될 것이므로 좋지 않습니다. 물론 우리는 unsubscribe()
라는 함수를 호출하면 됩니다. 하지만 이보다 더 쉽고 좋은 강력한 방법이 rx.js
에는 있습니다.
만약 아직 Observable
에 대해 완전히 이해하지 못했다면, 이전의 포스팅을 참고해 주세요.
rx.js
의 오퍼레이터(operator)를 사용하여 unsubscribe()
함수의 호출 없이 Observable
을 완료할 수 있습니다. 이 메소드를 사용하여 서브스크립션을 완료하는 방법은 unsubscribe()
함수를 호출하는 것보다 더 선호됩니다.
저는 각 rx.js
의 오퍼레이터를 설명하기 위해서 rxmarbles.com의 이미지를 포함할것입니다. 이미지에서 위의 화살표는 여러개의 값을 발산(emit)하는 원래의 Observable
을 나타낸다는 것을 기억하세요. 각 사이클은 한 개의 발산(emit)입니다. 그리고 아래의 화살표는 오퍼레이터가 완료되기 전에 갖는 데이터 스트림입니다. 만약 아직 rxmarbles를 잘 모른다면, 최대한 빨리 볼 수 있기를 바랍니다. rx.js 의 오퍼레이터가 어떻가 동작하는지 이해하는데 아주 큰 도움을 줍니다.
.first()
오직 첫번째 값만 필요하다면 fisrt()
를 사용하세요.Observable
은 첫번째 값만 전달하고 완료합니다.
사용 예
주로 API 요청을 할 때,first
를 사용할 수 있습니다.
import { Component } from '@angular/core';
import { ApiClient } from '../client/apiclient';
@Component({
selector: 'example-component',
templateUrl: './template.html',
})
export class ExampleComponent {
constructor(
public client: ApiClient,
){}
// api call that takes one response and then completes
public fetchUsers() {
this.client.fetchUsers()
.first()
.subscribe((users: IUser[]) {
// do stuff with your users here
})
}
public ngOnInit() {
this.fetchUsers();
}
}
.take()
최대로 수행할 횟수를 지정하기를 원한다면, take
를 사용하면 됩니다. take
는 지정한 횟수만큼의 값을 발산하는 Observable
을 반환합니다.
사용 예
만약 첫 번째 값은 null
일 수 있으나, 두번째 값은 반드시 값이 존재하는 로직이라면 take
를 사용하기 적절합니다. 저는 때로는 ngrx/store 로부터 데이터를 선택할때 이 함수를 사용합니다. 데이터를 요청할 때, store는 비어있을 수 있기 때문입니다. 그럼 첫번째 값은 null이 됩니다. 그리고 조금 뒤에 데이터가 받아서 서브스크립션자변수에 채워집니다. 그렇게 되면 take(2)
는 아주 적절하게 동작됩니다.
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { IState } from '../reducers';
@Component({
selector: 'example-component',
templateUrl: './template.html',
})
export class ExampleComponent {
constructor(
public store: Store<IState>,
){}
// get the users from your ngrx/store
// it can happen that it first is empty
// the second time there might be users, then it completes
public fetchUsersFromStore() {
this.store.select(getUsers)
.take(2)
.subscribe((users: IUser[]) {
// do stuff with your users here
})
}
public ngOnInit() {
this.fetchUsersFromStore();
}
}
.elementAt()
take
가 Observable
변수가 발산하는 최대 값을 지정한다면, elementAt
은 인덱스를 지정하여 받을 수 있도록 합니다. 즉, elementAt(2)
를 사용하면 Observable
변수가 세 번째로 발산하는 값을 받습니다. elementAt
함수는 세번째 값이 올때까지 기다리며, 그 후 종료합니다.
사용 예
예를 들면 세 번째 클릭했을 때, 무언가 동작을 취하는 시나리오가 있을 수 있습니다.
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { IState } from '../reducers';
@Component({
selector: 'example-component',
templateUrl: './template.html',
})
export class ExampleComponent {
public clicks$: Observable<any>;
// only take the third click
// then complete
public listenToClicks() {
this.clicks$
.elementAt(2)
.subscribe((thirdClick: any) => {
// do something with the third click
});
}
public ngOnInit() {
this.clicks$ = Observable.fromEvent(document.getElementById(button), 'click');
this.listenToClicks();
}
}
.takeUntil()
두 개의 Observable
변수가 필요한 takeUntil
은 이해하기에 조금 더 어렵습니다. takeUntil
은 두 번째 Observable
변수에서 무언가 값을 발산(emit)하거나 종료될 때까지 값을 발산합니다.
사용 예
특정 페이지에 웹소켓을 열어 리슨(listen)하고 있다고 생각 해 봅시다. 물론 페이지에 머물고 있는 동안, 웹소켓이 열러있어 서브스크립션을 유지하기를 원할것입니다. 이때, takeUntil
을 사용하면 라우터가 변할 때(routeChange
) 자동으로 서브스크립션이 해지(unsubscribe)됩니다.
역자주: Angular의 router.events는 자체가 Observable 변수 입니다. 여기에 rx.js의 오퍼레이터 filter를 걸어 NavigationStart(URL이 변경될때 발생) 이벤트의 발생을 서브스크립션합니다. 다음은 filter에 대한 rxmarbles의 그림입니다.
import { Component } from '@angular/core';
import { NavigationStart, Router } from '@angular/router';
import { Observable } from 'rxjs/Rx';
import { socketService } from '../services/socket';
import { IState } from '../reducers';
@Component({
selector: 'example-component',
templateUrl: './template.html',
})
export class ExampleComponent {
public messages$: Observable<any>;
public routeChange$: Observable<any>;
constructor(
public socket: socketService,
public router: Router,
){}
// listen to the socket untill there
// is an event of NavigationStart
// then complete
public listenToSocket() {
this.messages$
.takeUntil(this.routeChange$)
.subscribe((messages: any) => {
// do something with the messages here
})
}
public ngOnInit() {
this.messages$ = this.socket.messages;
this.routeChange$ = this.router.events.filter(event => event instanceof NavigationStart);
this.listenToSocket();
}
.takeWhile()
마지막은 필터처럼 사용될 수 있는 takeWhile
입니다. Observable
이 발산하는 각 값은 takeWhile
이 받습니다. 그리고 받은 값을 조건문과 비교하여 불린값을 반환합니다. 결과가 거짓(false)이면 Observable
은 종료됩니다.
사용 예
ngrx/store 에서 특정 데이터의 수신이 완료될 수도 있는 상황에 대하여 takeWhile
을 사용할 수 있습니다.
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { IState } from '../reducers';
@Component({
selector: 'example-component',
templateUrl: './template.html',
})
export class ExampleComponent {
constructor(
public store: Store<IState>,
){}
// get the users from your ngrx/store
// take values until the length is larger than 0
// then complete
public fetchUsersFromStore() {
this.store.select(getUsers)
.takeWhile(users => users.length > 0)
.subscribe((users: IUser[]) {
// do stuff with your users here
})
}
public ngOnInit() {
this.fetchUsersFromStore();
}
}
결론
위 예제들은 실제 잘 사용되지는 않겠지만, first
, take
, elementAt
, takeWhile
, takeUntil
을 전체적으로 unsubscribe()
를 사용하지 않고 서브스크립션을 관리하는 방법에 대해 이해하기에는 좋은 예제들입니다.
읽어주셔서 감사합니다. 아래는 번역하지 않겠습니다. 😊 다만 저자에 대한 감사의 표시로 아래 링크들은 그대로 걸어놓습니다.
저자의 다른 글
- https://hackernoon.com/understanding-creating-and-subscribing-to-observables-in-angular-426dbf0b04a3
- https://hackernoon.com/managing-large-s-css-projects-using-the-inverted-triangle-architecture-3c03e4b1e6df
- https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464
- https://hackernoon.com/an-angular-2-webpack-setup-for-development-and-production-3ea8bcc35e24
- https://hackernoon.com/global-http-request-error-catching-in-angular-486a319f59ab
Follow me on Medium or twitter and let’s connect on LinkedIn
'Javascript&Typescript > Angular2' 카테고리의 다른 글
[번역] 아직도 NgZone이 단순하게 Angular의 변화감지(Change Detection)를 위해서만 필요하다고 생각하시나요? (0) | 2018.04.23 |
---|---|
[번역] Angular에서 Zones(zone.js)의 역할 (0) | 2018.04.15 |
angular-cli를 이용한 Angular2 시작하기 (Quick Start) (2) | 2017.05.25 |
- Total
- Today
- Yesterday
- observable
- Swift
- lua table
- 타입스크립트
- 안시 색상
- angular2
- git proxy
- Angular
- zone
- 챗봇
- JavaScript
- 우분투 16.04
- 리눅스 터미널 색상
- NgZone
- C언어
- terminal 색
- qemu linux arm
- 스위프트
- Zone.js
- itoa
- QT
- git 설정
- 안시 컬러
- vim
- ZONES
- ansi color
- typeScript
- ECMA2015
- 폰트 조정
- Rx.js
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |