[리엑티브 연습] flatMap, concatMap, switchMap
안녕하세요. 블랙진입니다.
리엑티브 연습 포스팅입니다.
이터러밍 상황에서 flatMap, concatMap, switchMap 어떻게 동작되는지 살펴보겠습니다.
FlatMap
새로운 Observable 흐름을 만들어 주며 데이터의 흐름은 보장되지 않습니다.
val balls = listOf("하나", "둘", "셋")
Observable.interval(100L, TimeUnit.MILLISECONDS)
.map(Long::toInt)
.map { id -> balls[id] }
.take(balls.size.toLong())
.flatMap { ball ->
Observable.interval(200, TimeUnit.MILLISECONDS)
.map { "$ball ☆" }.take(2)
}
.subscribe(::println)
Thread.sleep(2000)
interval 함수는 일정한 간격을 가지고 데이터를 발행합니다. 0부터 주어진 시간 간격을 가지고 1씩 증가합니다.
|
0.1초 |
0.2초 |
0.3초 |
0.4초 |
0.5초 |
0.6초 |
0.7초 |
1OB |
하나 |
둘 |
셋 |
|
|
|
|
2OB |
|
|
하나 ☆ |
|
하나 ☆ |
|
|
2OB |
|
|
|
둘 ☆ |
|
둘 ☆ |
|
2OB |
|
|
|
|
셋 ☆ |
|
셋 ☆ |
표에 있는 시간순으로 데이터가 발행됩니다. 이를 순서대로 나열하면 아래와 같습니다.
하나 ☆
둘 ☆
하나 ☆
셋 ☆
둘 ☆
셋 ☆
이게 이터리밍 되었을 때의 데이터 입니다.
ConcatMap
먼저 들어온 데이터 순서대로 처리해서 결과를 낼 수 있도록 보장해줍니다.
Observable.interval(100L, TimeUnit.MILLISECONDS)
.map(Long::toInt)
.map { id -> balls[id] }
.take(balls.size.toLong())
.concatMap { ball ->
Observable.interval(200, TimeUnit.MILLISECONDS)
.map { "$ball ☆" }.take(2)
}
.subscribe(::println)
Thread.sleep(2000)
flatMap만 concatMap으로 변경했습니다.
|
0.1초 |
0.2초 |
0.3초 |
0.4초 |
0.5초 |
0.6초 |
0.7초 |
0.8초 |
0.9초 |
1.0초 |
1.1초 |
1.2초 |
1.3초 |
1OB |
하나 |
둘 |
셋 |
|
|
|
|
|
|
|
|
|
|
2OB |
|
|
하나 ☆ |
|
하나 ☆ |
|
|
|
|
|
|
|
|
2OB |
|
|
|
|
|
|
둘 ☆ |
|
둘 ☆ |
|
|
|
|
2OB |
|
|
|
|
|
|
|
|
|
|
셋 ☆ |
|
셋 ☆ |
표에 있는 시간순으로 데이터가 발행됩니다. 이를 순서대로 나열하면 아래와 같습니다.
하나 ☆
하나 ☆
둘 ☆
둘 ☆
셋 ☆
셋 ☆
이터리밍이 발생하지 않고 들어간 데이터 순서대로 발생하고 있는것을 확인할 수 있습니다.
SwitchMap
순서를 보장하기 위해 기존에 진행 중이던 작업을 바로 중단합니다.
Observable.interval(100L, TimeUnit.MILLISECONDS)
.map(Long::toInt)
.map { id -> balls[id] }
.take(balls.size.toLong())
.switchMap { ball ->
Observable.interval(200, TimeUnit.MILLISECONDS)
.map { "$ball ☆" }.take(2)
}
.subscribe(::println)
Thread.sleep(2000)
flatMap만 switchMap으로 변경했습니다.
| 0.1초 | 0.2초 | 0.3초 | 0.4초 | 0.5초 | 0.6초 | 0.7초 |
1OB | 하나 | 둘 | 셋 |
|
|
|
|
2OB | 구독 | 중지 |
|
|
|
| |
2OB |
| 구독 | 중지 |
|
|
|
|
2OB |
|
| 구독 |
| 셋 ☆ |
| 셋 ☆ |
표에 있는 시간순으로 데이터가 발행됩니다. 이를 순서대로 나열하면 아래와 같습니다.
셋 ☆
셋 ☆
표에서 보듯 2OB가 구독되었지만 1OB가 데이터를 보냈으므로 바로 중지가 됩니다.
주의사항
위에 적은 0.1초 0.2초 ... 에 따른 1OB, 2OB 결과는 직접 시간을 찍어본게 아닌 "doOnNext()를 통해 이런식으로 결과가 나오니깐 표가 이렇게 되겠구나라"는 저의 뇌피셜입니다. 연습용 포스팅 이지만 혹시나 오해가 되지 않게 참고 부탁드립니다.