RxJS๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํ์ํ์ธ์. ์ต์ ๋ฒ๋ธ ์คํธ๋ฆผ, ํจํด ๋ฐ ๋ฐ์์ฑ๊ณผ ํ์ฅ์ฑ์ด ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ์ค์ฉ์ ์ธ ์ ์ฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.
์๋ฐ์คํฌ๋ฆฝํธ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ: RxJS ํจํด & ์ต์ ๋ฒ๋ธ ์คํธ๋ฆผ
๋์์์ด ๋ฐ์ ํ๋ ํ๋ ์น ๊ฐ๋ฐ ํ๊ฒฝ์์ ๋ฐ์์ฑ ์๊ณ , ํ์ฅ ๊ฐ๋ฅํ๋ฉฐ, ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ(RP)์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด์ ๋ณ๊ฒฝ ์ฌํญ์ ์ ํํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ํจ๋ฌ๋ค์์ ์ ๊ณตํฉ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์์ RP๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ์ธ๊ธฐ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค RxJS(Reactive Extensions for JavaScript)๋ ๊ฒฌ๊ณ ํ๊ณ ๋ค์ฌ๋ค๋ฅํ ๋๊ตฌ๋ก ๋๋ณด์ ๋๋ค.
๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ด๋ ๋ฌด์์ธ๊ฐ?
ํต์ฌ์ ์ผ๋ก, ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ๊ณผ ๋ณ๊ฒฝ ์ฌํญ์ ์ ํ๋ฅผ ๋ค๋ฃจ๋ ๊ฒ์ ๋๋ค. ํ๋์ ์ ์ ์ ๋ฐ์ดํธํ๋ฉด ๊ด๋ จ ์์์ด ์๋์ผ๋ก ์ฌ๊ณ์ฐ๋๋ ์คํ๋ ๋์ํธ๋ฅผ ์์ํด ๋ณด์ธ์. ์ด๊ฒ์ด ๋ฐ๋ก RP์ ๋ณธ์ง์ ๋๋ค. ์ฆ, ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ์ ์ธ์ ์ด๊ณ ํจ์จ์ ์ธ ๋ฐฉ์์ผ๋ก ๋ฐ์ํ๋ ๊ฒ์ ๋๋ค.
์ ํต์ ์ธ ๋ช ๋ นํ ํ๋ก๊ทธ๋๋ฐ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ ์ด๋ฒคํธ์ ๋ํ ์๋ต์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ์๋์ผ๋ก ์ ๋ฐ์ดํธํ๋ ์์ ์ ํฌํจํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด๋ ํนํ ๋คํธ์ํฌ ์์ฒญ์ด๋ ์ฌ์ฉ์ ์ํธ์์ฉ๊ณผ ๊ฐ์ ๋น๋๊ธฐ ์์ ์ ๋ค๋ฃฐ ๋ ๋ณต์กํ๊ณ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ก ์ด์ด์ง ์ ์์ต๋๋ค. RP๋ ๋ชจ๋ ๊ฒ์ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ผ๋ก ์ทจ๊ธํ๊ณ ์ด๋ฌํ ์คํธ๋ฆผ์ ๋ณํ, ํํฐ๋ง ๋ฐ ๊ฒฐํฉํ๋ ์ฐ์ฐ์๋ฅผ ์ ๊ณตํจ์ผ๋ก์จ ์ด๋ฅผ ๋จ์ํํฉ๋๋ค.
RxJS ์๊ฐ: ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ํ ๋ฐ์ํ ํ์ฅ
RxJS๋ ์ต์ ๋ฒ๋ธ ์ํ์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ ๋ฐ ์ด๋ฒคํธ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋จ์ ๊ตฌ์ฑํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ฝ๊ฒ ์กฐ์ํ ์ ์๋ ๊ฐ๋ ฅํ ์ฐ์ฐ์ ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. RxJS๋ ์ต์ ๋ฒ ํจํด, ์ดํฐ๋ ์ดํฐ ํจํด ๋ฐ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ ์ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฒคํธ ๋๋ ๋ฐ์ดํฐ ์ํ์ค๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.
RxJS์ ํต์ฌ ๊ฐ๋ :
- ์ต์ ๋ฒ๋ธ(Observables): ํ๋ ์ด์์ ์ต์ ๋ฒ๊ฐ ๊ด์ฐฐํ ์ ์๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋ํ๋ ๋๋ค. ์ง์ฐ(lazy) ํ๊ฐ ๋ฐฉ์์ผ๋ก ๋์ํ๋ฉฐ, ๊ตฌ๋ ๋ ๋๋ง ๊ฐ์ ๋ฐํํ๊ธฐ ์์ํฉ๋๋ค.
- ์ต์ ๋ฒ(Observers): ์ต์ ๋ฒ๋ธ์ด ๋ฐํํ ๋ฐ์ดํฐ๋ฅผ ์๋นํฉ๋๋ค. ๊ฐ์ ๋ฐ๊ธฐ ์ํ
next()
, ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํerror()
, ์คํธ๋ฆผ์ ๋์ ์๋ฆฌ๋complete()
์ ์ธ ๊ฐ์ง ๋ฉ์๋๋ฅผ ๊ฐ์ง๋๋ค. - ์ฐ์ฐ์(Operators): ์ต์ ๋ฒ๋ธ์ ๋ณํ, ํํฐ๋ง, ๊ฒฐํฉ ๋๋ ์กฐ์ํ๋ ํจ์์ ๋๋ค. RxJS๋ ๋ค์ํ ๋ชฉ์ ์ ์ํ ๋ฐฉ๋ํ ์ฐ์ฐ์๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์๋ธ์ ํธ(Subjects): ์ต์ ๋ฒ๋ธ๊ณผ ์ต์ ๋ฒ์ ์ญํ ์ ๋ชจ๋ ์ํํ์ฌ, ์ฌ๋ฌ ๊ตฌ๋ ์์๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ฉํฐ์บ์คํธํ๊ณ ์คํธ๋ฆผ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ด ๋ฃ์ ์ ์์ต๋๋ค.
- ์ค์ผ์ค๋ฌ(Schedulers): ์ต์ ๋ฒ๋ธ์ ๋์์ฑ์ ์ ์ดํ์ฌ ์ฝ๋๋ฅผ ๋๊ธฐ์ ๋๋ ๋น๋๊ธฐ์ ์ผ๋ก, ๋ค๋ฅธ ์ค๋ ๋์์ ๋๋ ํน์ ์ง์ฐ ์๊ฐ์ผ๋ก ์คํํ ์ ์๊ฒ ํฉ๋๋ค.
์ต์ ๋ฒ๋ธ ์คํธ๋ฆผ ์์ธํ ์์๋ณด๊ธฐ
์ต์ ๋ฒ๋ธ์ RxJS์ ๊ธฐ๋ฐ์ ๋๋ค. ์๊ฐ์ ๋ฐ๋ผ ๊ด์ฐฐํ ์ ์๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋ํ๋ ๋๋ค. ์ต์ ๋ฒ๋ธ์ ๊ตฌ๋ ์์๊ฒ ๊ฐ์ ๋ฐํํ๋ฉฐ, ๊ตฌ๋ ์๋ ์ด ๊ฐ๋ค์ ์ฒ๋ฆฌํ๊ฑฐ๋ ๋ฐ์ํ ์ ์์ต๋๋ค. ๋ฐ์ดํฐ๊ฐ ์์ค์์ ํ๋ ์ด์์ ์๋น์๋ก ํ๋ฅด๋ ํ์ดํ๋ผ์ธ์ผ๋ก ์๊ฐํ ์ ์์ต๋๋ค.
์ต์ ๋ฒ๋ธ ์์ฑํ๊ธฐ:
RxJS๋ ์ต์ ๋ฒ๋ธ์ ์์ฑํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค:
Observable.create()
: ์ต์ ๋ฒ๋ธ์ ๋์์ ์๋ฒฝํ๊ฒ ์ ์ดํ ์ ์๋ ์ ์์ค ๋ฉ์๋์ ๋๋ค.from()
: ๋ฐฐ์ด, ํ๋ก๋ฏธ์ค, ์ดํฐ๋ฌ๋ธ ๋๋ ์ต์ ๋ฒ๋ธ๊ณผ ์ ์ฌํ ๊ฐ์ฒด๋ฅผ ์ต์ ๋ฒ๋ธ๋ก ๋ณํํฉ๋๋ค.of()
: ๊ฐ์ ์ํ์ค๋ฅผ ๋ฐํํ๋ ์ต์ ๋ฒ๋ธ์ ์์ฑํฉ๋๋ค.interval()
: ์ง์ ๋ ๊ฐ๊ฒฉ์ผ๋ก ์ซ์ ์ํ์ค๋ฅผ ๋ฐํํ๋ ์ต์ ๋ฒ๋ธ์ ์์ฑํฉ๋๋ค.timer()
: ์ง์ ๋ ์ง์ฐ ์๊ฐ ํ์ ๋จ์ผ ๊ฐ์ ๋ฐํํ๊ฑฐ๋, ์ง์ฐ ์๊ฐ ํ ๊ณ ์ ๋ ๊ฐ๊ฒฉ์ผ๋ก ์ซ์ ์ํ์ค๋ฅผ ๋ฐํํ๋ ์ต์ ๋ฒ๋ธ์ ์์ฑํฉ๋๋ค.fromEvent()
: DOM ์์๋ ๋ค๋ฅธ ์ด๋ฒคํธ ์์ค๋ก๋ถํฐ ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๋ ์ต์ ๋ฒ๋ธ์ ์์ฑํฉ๋๋ค.
์์ : ๋ฐฐ์ด๋ก ์ต์ ๋ฒ๋ธ ์์ฑํ๊ธฐ
```javascript import { from } from 'rxjs'; const myArray = [1, 2, 3, 4, 5]; const myObservable = from(myArray); myObservable.subscribe( value => console.log('์์ :', value), error => console.error('์ค๋ฅ:', error), () => console.log('์๋ฃ๋จ') ); // ์ถ๋ ฅ: // ์์ : 1 // ์์ : 2 // ์์ : 3 // ์์ : 4 // ์์ : 5 // ์๋ฃ๋จ ```
์์ : ์ด๋ฒคํธ๋ก ์ต์ ๋ฒ๋ธ ์์ฑํ๊ธฐ
```javascript import { fromEvent } from 'rxjs'; const button = document.getElementById('myButton'); const clickObservable = fromEvent(button, 'click'); clickObservable.subscribe( event => console.log('๋ฒํผ ํด๋ฆญ๋จ!', event) ); ```
์ต์ ๋ฒ๋ธ ๊ตฌ๋ ํ๊ธฐ:
์ต์ ๋ฒ๋ธ๋ก๋ถํฐ ๊ฐ์ ๋ฐ๊ธฐ ์์ํ๋ ค๋ฉด subscribe()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ๋
ํด์ผ ํฉ๋๋ค. subscribe()
๋ฉ์๋๋ ์ต๋ ์ธ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ต๋๋ค:
next
: ์ต์ ๋ฒ๋ธ์ด ๋ฐํํ๋ ๊ฐ ๊ฐ์ ๋ํด ํธ์ถ๋ ํจ์์ ๋๋ค.error
: ์ต์ ๋ฒ๋ธ์ด ์ค๋ฅ๋ฅผ ๋ฐํํ ๊ฒฝ์ฐ ํธ์ถ๋ ํจ์์ ๋๋ค.complete
: ์ต์ ๋ฒ๋ธ์ด ์๋ฃ๋ ๋(์คํธ๋ฆผ์ ๋์ ์๋ฆด ๋) ํธ์ถ๋ ํจ์์ ๋๋ค.
subscribe()
๋ฉ์๋๋ ์ต์ ๋ฒ๋ธ๊ณผ ์ต์ ๋ฒ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ํ๋ด๋ Subscription ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. Subscription ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์ต์ ๋ฒ๋ธ ๊ตฌ๋
์ ์ทจ์ํ๊ณ ๋ ์ด์ ๊ฐ์ด ๋ฐํ๋์ง ์๋๋ก ํ ์ ์์ต๋๋ค.
์ต์ ๋ฒ๋ธ ๊ตฌ๋ ์ทจ์ํ๊ธฐ:
๊ตฌ๋
์ทจ์๋ ํนํ ์ค๋ ์ง์๋๋ ์ต์ ๋ฒ๋ธ์ด๋ ๊ฐ์ ์์ฃผ ๋ฐํํ๋ ์ต์ ๋ฒ๋ธ์ ๋ค๋ฃฐ ๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. Subscription ๊ฐ์ฒด์ unsubscribe()
๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ต์ ๋ฒ๋ธ ๊ตฌ๋
์ ์ทจ์ํ ์ ์์ต๋๋ค.
```javascript import { interval } from 'rxjs'; const myInterval = interval(1000); const subscription = myInterval.subscribe( value => console.log('์ธํฐ๋ฒ:', value) ); // 5์ด ํ ๊ตฌ๋ ์ทจ์ setTimeout(() => { subscription.unsubscribe(); console.log('๊ตฌ๋ ์ทจ์๋จ!'); }, 5000); // ์ถ๋ ฅ (๋๋ต): // ์ธํฐ๋ฒ: 0 // ์ธํฐ๋ฒ: 1 // ์ธํฐ๋ฒ: 2 // ์ธํฐ๋ฒ: 3 // ์ธํฐ๋ฒ: 4 // ๊ตฌ๋ ์ทจ์๋จ! ```
RxJS ์ฐ์ฐ์: ๋ฐ์ดํฐ ์คํธ๋ฆผ ๋ณํ ๋ฐ ํํฐ๋ง
RxJS ์ฐ์ฐ์๋ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํต์ฌ์ ๋๋ค. ์ด ์ฐ์ฐ์๋ค์ ์ฌ์ฉํ๋ฉด ์ ์ธ์ ์ด๊ณ ์กฐํฉ ๊ฐ๋ฅํ ๋ฐฉ์์ผ๋ก ์ต์ ๋ฒ๋ธ์ ๋ณํ, ํํฐ๋ง, ๊ฒฐํฉ ๋ฐ ์กฐ์ํ ์ ์์ต๋๋ค. ๊ฐ๊ฐ ํน์ ๋ชฉ์ ์ ๊ฐ์ง ์๋ง์ ์ฐ์ฐ์๊ฐ ์์ผ๋ฉฐ, ๊ฐ์ฅ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋๋ ์ฐ์ฐ์ ๋ช ๊ฐ์ง๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
๋ณํ ์ฐ์ฐ์:
map()
: ์ต์ ๋ฒ๋ธ์ด ๋ฐํํ ๊ฐ ๊ฐ์ ํจ์๋ฅผ ์ ์ฉํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค. ๋ฐฐ์ด์map()
๋ฉ์๋์ ์ ์ฌํฉ๋๋ค.pluck()
: ์ต์ ๋ฒ๋ธ์ด ๋ฐํํ ๊ฐ ๊ฐ์์ ํน์ ์์ฑ์ ์ถ์ถํฉ๋๋ค.scan()
: ์์ค ์ต์ ๋ฒ๋ธ์ ๋ํด ๋์ฐ๊ธฐ ํจ์๋ฅผ ์ ์ฉํ๊ณ ๊ฐ ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.buffer()
: ์์ค ์ต์ ๋ฒ๋ธ์ ๊ฐ๋ค์ ๋ฐฐ์ด๋ก ์์งํ๊ณ ํน์ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ฉด ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค.window()
:buffer()
์ ์ ์ฌํ์ง๋ง, ๋ฐฐ์ด์ ๋ฐํํ๋ ๋์ ๊ฐ์ ์ฐฝ(window)์ ๋ํ๋ด๋ ์ต์ ๋ฒ๋ธ์ ๋ฐํํฉ๋๋ค.
์์ : map()
์ฐ์ฐ์ ์ฌ์ฉํ๊ธฐ
```javascript import { from } from 'rxjs'; import { map } from 'rxjs/operators'; const numbers = from([1, 2, 3, 4, 5]); const squaredNumbers = numbers.pipe( map(x => x * x) ); squaredNumbers.subscribe(value => console.log('์ ๊ณฑ:', value)); // ์ถ๋ ฅ: // ์ ๊ณฑ: 1 // ์ ๊ณฑ: 4 // ์ ๊ณฑ: 9 // ์ ๊ณฑ: 16 // ์ ๊ณฑ: 25 ```
ํํฐ๋ง ์ฐ์ฐ์:
filter()
: ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ๊ฐ๋ง ๋ฐํํฉ๋๋ค.debounceTime()
: ์๋ก์ด ๊ฐ์ด ๋ฐํ๋์ง ์๊ณ ์ผ์ ์๊ฐ์ด ์ง๋ ๋๊น์ง ๊ฐ์ ๋ฐํ์ ์ง์ฐ์ํต๋๋ค. ์ฌ์ฉ์ ์ ๋ ฅ์ ์ฒ๋ฆฌํ๊ณ ๊ณผ๋ํ ์์ฒญ์ ๋ฐฉ์งํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.distinctUntilChanged()
: ์ด์ ๊ฐ๊ณผ ๋ค๋ฅธ ๊ฐ๋ง ๋ฐํํฉ๋๋ค.take()
: ์ต์ ๋ฒ๋ธ์์ ์ฒ์ N๊ฐ์ ๊ฐ๋ง ๋ฐํํฉ๋๋ค.skip()
: ์ต์ ๋ฒ๋ธ์์ ์ฒ์ N๊ฐ์ ๊ฐ์ ๊ฑด๋๋ฐ๊ณ ๋๋จธ์ง ๊ฐ์ ๋ฐํํฉ๋๋ค.
์์ : filter()
์ฐ์ฐ์ ์ฌ์ฉํ๊ธฐ
```javascript import { from } from 'rxjs'; import { filter } from 'rxjs/operators'; const numbers = from([1, 2, 3, 4, 5, 6]); const evenNumbers = numbers.pipe( filter(x => x % 2 === 0) ); evenNumbers.subscribe(value => console.log('์ง์:', value)); // ์ถ๋ ฅ: // ์ง์: 2 // ์ง์: 4 // ์ง์: 6 ```
๊ฒฐํฉ ์ฐ์ฐ์:
merge()
: ์ฌ๋ฌ ์ต์ ๋ฒ๋ธ์ ๋จ์ผ ์ต์ ๋ฒ๋ธ๋ก ๋ณํฉํฉ๋๋ค.concat()
: ์ฌ๋ฌ ์ต์ ๋ฒ๋ธ์ ์ฐ๊ฒฐํ์ฌ ๊ฐ ์ต์ ๋ฒ๋ธ์ ๊ฐ์ ์์๋๋ก ๋ฐํํฉ๋๋ค.combineLatest()
: ์ฌ๋ฌ ์ต์ ๋ฒ๋ธ์ ์ต์ ๊ฐ์ ๊ฒฐํฉํ๊ณ , ์์ค ์ต์ ๋ฒ๋ธ ์ค ํ๋๋ผ๋ ๊ฐ์ ๋ฐํํ ๋๋ง๋ค ์๋ก์ด ๊ฐ์ ๋ฐํํฉ๋๋ค.zip()
: ์ฌ๋ฌ ์ต์ ๋ฒ๋ธ์ ๊ฐ์ ์ธ๋ฑ์ค ๊ธฐ๋ฐ์ผ๋ก ๊ฒฐํฉํ๊ณ ๊ฐ ์กฐํฉ์ ๋ํด ์๋ก์ด ๊ฐ์ ๋ฐํํฉ๋๋ค.withLatestFrom()
: ๋ค๋ฅธ ์ต์ ๋ฒ๋ธ์ ์ต์ ๊ฐ์ ์์ค ์ต์ ๋ฒ๋ธ์ ํ์ฌ ๊ฐ๊ณผ ๊ฒฐํฉํฉ๋๋ค.
์์ : combineLatest()
์ฐ์ฐ์ ์ฌ์ฉํ๊ธฐ
```javascript import { interval, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; const interval1 = interval(1000); const interval2 = interval(2000); const combinedIntervals = combineLatest( interval1, interval2, (x, y) => `์ธํฐ๋ฒ 1: ${x}, ์ธํฐ๋ฒ 2: ${y}` ); combinedIntervals.subscribe(value => console.log(value)); // ์ถ๋ ฅ (๋๋ต): // ์ธํฐ๋ฒ 1: 0, ์ธํฐ๋ฒ 2: 0 // ์ธํฐ๋ฒ 1: 1, ์ธํฐ๋ฒ 2: 0 // ์ธํฐ๋ฒ 1: 1, ์ธํฐ๋ฒ 2: 1 // ์ธํฐ๋ฒ 1: 2, ์ธํฐ๋ฒ 2: 1 // ์ธํฐ๋ฒ 1: 2, ์ธํฐ๋ฒ 2: 2 // ... ```
์ผ๋ฐ์ ์ธ RxJS ํจํด
RxJS๋ ์ผ๋ฐ์ ์ธ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ์์ ์ ๋จ์ํํ ์ ์๋ ๋ช ๊ฐ์ง ๊ฐ๋ ฅํ ํจํด์ ์ ๊ณตํฉ๋๋ค:
๋๋ฐ์ด์ฑ(Debouncing):
debounceTime()
์ฐ์ฐ์๋ ์๋ก์ด ๊ฐ์ด ๋ฐํ๋์ง ์๊ณ ์ผ์ ์๊ฐ์ด ์ง๋ ๋๊น์ง ๊ฐ์ ๋ฐํ์ ์ง์ฐ์ํค๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ ์๋ฒ์ ๋ํ ๊ณผ๋ํ ์์ฒญ์ ๋ฐฉ์งํ๋ ค๋ ๊ฒ์ ์ฟผ๋ฆฌ๋ ์์ ์ ์ถ๊ณผ ๊ฐ์ ์ฌ์ฉ์ ์
๋ ฅ์ ์ฒ๋ฆฌํ๋ ๋ฐ ํนํ ์ ์ฉํฉ๋๋ค.
์์ : ๊ฒ์ ์ ๋ ฅ ๋๋ฐ์ด์ฑ
```javascript import { fromEvent } from 'rxjs'; import { map, debounceTime, distinctUntilChanged } from 'rxjs/operators'; const searchInput = document.getElementById('searchInput'); const searchObservable = fromEvent(searchInput, 'keyup').pipe( map((event: any) => event.target.value), debounceTime(300), // ๊ฐ ํค ์ ๋ ฅ ํ 300ms ๋๊ธฐ distinctUntilChanged() // ๊ฐ์ด ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ง ๋ฐํ ); searchObservable.subscribe(searchTerm => { console.log('๊ฒ์์ด:', searchTerm); // ํด๋น ์ฉ์ด๋ก ๊ฒ์ํ๊ธฐ ์ํด API ์์ฒญ }); ```
์ฐ๋กํ๋ง(Throttling):
throttleTime()
์ฐ์ฐ์๋ ์ต์ ๋ฒ๋ธ์์ ๊ฐ์ด ๋ฐํ๋๋ ์๋๋ฅผ ์ ํํฉ๋๋ค. ์ง์ ๋ ์๊ฐ ์ฐฝ ๋์ ๋ฐํ๋ ์ฒซ ๋ฒ์งธ ๊ฐ์ ๋ฐํํ๊ณ , ์ฐฝ์ด ๋ซํ ๋๊น์ง ํ์ ๊ฐ์ ๋ฌด์ํฉ๋๋ค. ์ด๋ ์คํฌ๋กค ์ด๋ฒคํธ๋ ๋ฆฌ์ฌ์ด์ฆ ์ด๋ฒคํธ์ ๊ฐ์ ์ด๋ฒคํธ์ ๋น๋๋ฅผ ์ ํํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
์ค์์นญ(Switching):
switchMap()
์ฐ์ฐ์๋ ์์ค ์ต์ ๋ฒ๋ธ์์ ์๋ก์ด ๊ฐ์ด ๋ฐํ๋ ๋๋ง๋ค ์๋ก์ด ์ต์ ๋ฒ๋ธ๋ก ์ ํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ ์๋ก์ด ์์ฒญ์ด ์์๋ ๋ ๋ณด๋ฅ ์ค์ธ ์์ฒญ์ ์ทจ์ํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ๊ฒ์ ์
๋ ฅ๋์ ์ ๋ฌธ์๋ฅผ ์
๋ ฅํ ๋ ์ด์ ๊ฒ์ ์์ฒญ์ ์ทจ์ํ๊ธฐ ์ํด switchMap()
์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ : ์๋ ์์ฑ ๊ฒ์์ switchMap()
์ฌ์ฉํ๊ธฐ
```javascript import { fromEvent, of } from 'rxjs'; import { map, debounceTime, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators'; const searchInput = document.getElementById('searchInput'); const searchObservable = fromEvent(searchInput, 'keyup').pipe( map((event: any) => event.target.value), debounceTime(300), distinctUntilChanged(), switchMap(searchTerm => { // ํด๋น ์ฉ์ด๋ก ๊ฒ์ํ๊ธฐ ์ํด API ์์ฒญ return searchAPI(searchTerm).pipe( catchError(error => { console.error('๊ฒ์ ์ค๋ฅ:', error); return of([]); // ์ค๋ฅ ์ ๋น ๋ฐฐ์ด ๋ฐํ }) ); }) ); searchObservable.subscribe(results => { console.log('๊ฒ์ ๊ฒฐ๊ณผ:', results); // ๊ฒ์ ๊ฒฐ๊ณผ๋ก UI ์ ๋ฐ์ดํธ }); function searchAPI(searchTerm: string) { // API ์์ฒญ ์๋ฎฌ๋ ์ด์ return of([`${searchTerm}์ ๋ํ ๊ฒฐ๊ณผ 1`, `${searchTerm}์ ๋ํ ๊ฒฐ๊ณผ 2`]); } ```
RxJS์ ์ค์ฉ์ ์ธ ์ ์ฉ ์ฌ๋ก
RxJS๋ ๋ค์ํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉ๋ ์ ์๋ ๋ค์ฌ๋ค๋ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ฌ์ฉ์ ์
๋ ฅ ์ฒ๋ฆฌ: RxJS๋ ํค ์
๋ ฅ, ๋ง์ฐ์ค ํด๋ฆญ, ์์ ์ ์ถ๊ณผ ๊ฐ์ ์ฌ์ฉ์ ์
๋ ฅ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
debounceTime()
๋ฐthrottleTime()
๊ณผ ๊ฐ์ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ์ต์ ํํ๊ณ ๊ณผ๋ํ ์์ฒญ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค. - ๋น๋๊ธฐ ์์
๊ด๋ฆฌ: RxJS๋ ๋คํธ์ํฌ ์์ฒญ ๋ฐ ํ์ด๋จธ์ ๊ฐ์ ๋น๋๊ธฐ ์์
์ ๊ด๋ฆฌํ๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
switchMap()
๋ฐmergeMap()
๊ณผ ๊ฐ์ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ๋ณด๋ฅ ์ค์ธ ์์ฒญ์ ์ทจ์ํ ์ ์์ต๋๋ค. - ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ: RxJS๋ ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ ๋์๋ณด๋์ ๊ฐ์ ์ค์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ์ ํฉํฉ๋๋ค. ์ต์ ๋ฒ๋ธ์ ์น์์ผ(WebSockets) ๋๋ ์๋ฒ-์ ์ก ์ด๋ฒคํธ(SSE)์ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋ํ๋ด๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
- ์ํ ๊ด๋ฆฌ: RxJS๋ Angular, React ๋ฐ Vue.js์ ๊ฐ์ ํ๋ ์์ํฌ์์ ์ํ ๊ด๋ฆฌ ์๋ฃจ์ ์ผ๋ก ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์ต์ ๋ฒ๋ธ์ ์ ํ๋ฆฌ์ผ์ด์ ์ํ๋ฅผ ๋ํ๋ด๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ผ๋ฉฐ, ์ฐ์ฐ์๋ ์ฌ์ฉ์ ์์ ์ด๋ ์ด๋ฒคํธ์ ๋ํ ์๋ต์ผ๋ก ์ํ๋ฅผ ๋ณํํ๊ณ ์ ๋ฐ์ดํธํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
์ฃผ์ ํ๋ ์์ํฌ์ RxJS
Angular:
Angular๋ ๋น๋๊ธฐ ์์
์ ์ฒ๋ฆฌํ๊ณ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๊ด๋ฆฌํ๊ธฐ ์ํด RxJS์ ํฌ๊ฒ ์์กดํฉ๋๋ค. Angular์ HttpClient
์๋น์ค๋ ์ต์ ๋ฒ๋ธ์ ๋ฐํํ๋ฉฐ, RxJS ์ฐ์ฐ์๋ API ์์ฒญ์์ ๋ฐํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๊ณ ํํฐ๋งํ๋ ๋ฐ ๊ด๋ฒ์ํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค. Angular์ ๋ณ๊ฒฝ ๊ฐ์ง ๋ฉ์ปค๋์ฆ ๋ํ RxJS๋ฅผ ํ์ฉํ์ฌ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ๋ํ ์๋ต์ผ๋ก UI๋ฅผ ํจ์จ์ ์ผ๋ก ์
๋ฐ์ดํธํฉ๋๋ค.
์์ : Angular์ HttpClient์ RxJS ์ฌ์ฉํ๊ธฐ
```typescript
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class DataService {
private apiUrl = 'https://api.example.com/data';
constructor(private http: HttpClient) { }
getData(): Observable
React:
React์๋ RxJS์ ๋ํ ๋ด์ฅ ์ง์์ด ์์ง๋ง, rxjs-hooks
๋๋ use-rx
์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๊ฒ ํตํฉํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ React ์ปดํฌ๋ํธ ๋ด์์ ์ต์ ๋ฒ๋ธ์ ๊ตฌ๋
ํ๊ณ ๊ตฌ๋
์ ๊ด๋ฆฌํ ์ ์๋ ์ฌ์ฉ์ ์ ์ ํ
์ ์ ๊ณตํฉ๋๋ค. RxJS๋ React์์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ, ์ปดํฌ๋ํธ ์ํ ๊ด๋ฆฌ ๋ฐ ๋ฐ์ํ UI ๊ตฌ์ถ์ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
์์ : React Hooks์ RxJS ์ฌ์ฉํ๊ธฐ
```javascript import React, { useState, useEffect } from 'react'; import { Subject } from 'rxjs'; import { scan } from 'rxjs/operators'; function Counter() { const [count, setCount] = useState(0); const increment$ = new Subject(); useEffect(() => { const subscription = increment$.pipe( scan(acc => acc + 1, 0) ).subscribe(setCount); return () => subscription.unsubscribe(); }, []); return (
์นด์ดํธ: {count}
Vue.js:
Vue.js ๋ํ ๊ธฐ๋ณธ RxJS ํตํฉ ๊ธฐ๋ฅ์ด ์์ง๋ง, vue-rx
์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์ฌ์ฉํ๊ฑฐ๋ Vue ์ปดํฌ๋ํธ ๋ด์์ ์๋์ผ๋ก ๊ตฌ๋
์ ๊ด๋ฆฌํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค. RxJS๋ Vue.js์์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ์ปดํฌ๋ํธ ์ํ ๊ด๋ฆฌ์ ๊ฐ์ด React์ ์ ์ฌํ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
RxJS ์ฌ์ฉ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
- ์ต์ ๋ฒ๋ธ ๊ตฌ๋
์ทจ์: ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ ์ด์ ํ์ํ์ง ์์ ์ต์ ๋ฒ๋ธ์ ํญ์ ๊ตฌ๋
์ ์ทจ์ํ์ญ์์ค.
subscribe()
๋ฉ์๋๊ฐ ๋ฐํํ๋ Subscription ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ๋ ์ ์ทจ์ํฉ๋๋ค. pipe()
๋ฉ์๋ ์ฌ์ฉ:pipe()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ฐ์ฐ์๋ค์ ๊ฐ๋ ์ฑ ์๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ๋ฐฉ์์ผ๋ก ์ฐ๊ฒฐํ์ญ์์ค.- ์ค๋ฅ๋ฅผ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ:
catchError()
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์ค๋ฅ๊ฐ ์ต์ ๋ฒ๋ธ ์ฒด์ธ ์๋ก ์ ํ๋๋ ๊ฒ์ ๋ฐฉ์งํ์ญ์์ค. - ์ฌ๋ฐ๋ฅธ ์ฐ์ฐ์ ์ ํ: ํน์ ์ฌ์ฉ ์ฌ๋ก์ ์ ํฉํ ์ฐ์ฐ์๋ฅผ ์ ํํ์ญ์์ค. RxJS๋ ๋ฐฉ๋ํ ์ฐ์ฐ์๋ฅผ ์ ๊ณตํ๋ฏ๋ก ๊ทธ ๋ชฉ์ ๊ณผ ๋์์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- ์ต์ ๋ฒ๋ธ์ ๋จ์ํ๊ฒ ์ ์ง: ์ง๋์น๊ฒ ๋ณต์กํ ์ต์ ๋ฒ๋ธ์ ๋ง๋ค์ง ๋ง์ญ์์ค. ๋ณต์กํ ์์ ์ ๋ ์๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ์ต์ ๋ฒ๋ธ๋ก ๋๋์ญ์์ค.
๊ณ ๊ธ RxJS ๊ฐ๋
์๋ธ์ ํธ(Subjects):
์๋ธ์ ํธ๋ ์ต์ ๋ฒ๋ธ๊ณผ ์ต์ ๋ฒ์ ์ญํ ์ ๋ชจ๋ ์ํํฉ๋๋ค. ์ฌ๋ฌ ๊ตฌ๋ ์์๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ฉํฐ์บ์คํธํ๊ณ ์คํธ๋ฆผ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ด ๋ฃ์ ์ ์์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ ๋ค์ํ ์ ํ์ ์๋ธ์ ํธ๊ฐ ์์ต๋๋ค:
- Subject: ๋ชจ๋ ๊ตฌ๋ ์์๊ฒ ๊ฐ์ ๋ฉํฐ์บ์คํธํ๋ ๊ธฐ๋ณธ ์๋ธ์ ํธ์ ๋๋ค.
- BehaviorSubject: ์ด๊ธฐ ๊ฐ์ด ํ์ํ๋ฉฐ ์๋ก์ด ๊ตฌ๋ ์์๊ฒ ํ์ฌ ๊ฐ์ ๋ฐํํฉ๋๋ค.
- ReplaySubject: ์ง์ ๋ ์์ ๊ฐ์ ๋ฒํผ๋งํ๊ณ ์๋ก์ด ๊ตฌ๋ ์์๊ฒ ๋ค์ ์ฌ์ํฉ๋๋ค.
- AsyncSubject: ์ต์ ๋ฒ๋ธ์ด ์๋ฃ๋ ๋ ๋ง์ง๋ง ๊ฐ๋ง ๋ฐํํฉ๋๋ค.
์ค์ผ์ค๋ฌ(Schedulers):
์ค์ผ์ค๋ฌ๋ ์ต์ ๋ฒ๋ธ์ ๋์์ฑ์ ์ ์ดํฉ๋๋ค. ์ฝ๋๋ฅผ ๋๊ธฐ์ ๋๋ ๋น๋๊ธฐ์ ์ผ๋ก, ๋ค๋ฅธ ์ค๋ ๋์์ ๋๋ ํน์ ์ง์ฐ ์๊ฐ์ผ๋ก ์คํํ ์ ์๊ฒ ํฉ๋๋ค. RxJS๋ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ๋ด์ฅ ์ค์ผ์ค๋ฌ๋ฅผ ์ ๊ณตํฉ๋๋ค:
queueScheduler
: ํ์ฌ ์คํ ์ปจํ ์คํธ ์ดํ์ ํ์ฌ ์๋ฐ์คํฌ๋ฆฝํธ ์ค๋ ๋์์ ์คํ๋ ์์ ์ ์ค์ผ์คํฉ๋๋ค.asapScheduler
: ํ์ฌ ์คํ ์ปจํ ์คํธ ์ดํ ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ ํ์ฌ ์๋ฐ์คํฌ๋ฆฝํธ ์ค๋ ๋์์ ์คํ๋ ์์ ์ ์ค์ผ์คํฉ๋๋ค.asyncScheduler
:setTimeout
๋๋setInterval
์ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋ ์์ ์ ์ค์ผ์คํฉ๋๋ค.animationFrameScheduler
: ๋ค์ ์ ๋๋ฉ์ด์ ํ๋ ์์์ ์คํ๋ ์์ ์ ์ค์ผ์คํฉ๋๋ค.
๊ฒฐ๋ก
RxJS๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ฐ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ต์ ๋ฒ๋ธ, ์ฐ์ฐ์ ๋ฐ ์ผ๋ฐ์ ์ธ ํจํด์ ๋ง์คํฐํจ์ผ๋ก์จ ๋ ๋ฐ์์ฑ ์๊ณ ํ์ฅ ๊ฐ๋ฅํ๋ฉฐ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ์ ์์ต๋๋ค. Angular, React, Vue.js ๋๋ ์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์์ ํ๋ , RxJS๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๊ณ ๋ณต์กํ UI๋ฅผ ๊ตฌ์ถํ๋ ๋ฅ๋ ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
RxJS๋ก ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํ์ ๋ฐ์๋ค์ด๊ณ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ก์ด ๊ฐ๋ฅ์ฑ์ ์ด์ด๋ณด์ธ์!