RxSwiftのconcatMapはsubsequenceを得る処理自体を待つわけじゃない
やりたいこと
非同期処理のトリガー PublishRelay<Int>
によって、非同期処理 Single<Int>
が行われる。
トリガーは非同期処理が終わる前にも叩かれうるが、前の非同期処理が終わるまで、次の処理は待機したい。
方針
- 非同期処理が同時に走らないようにしたい
- つまり
flatMap
は使えない
- つまり
- トリガーが叩かれた回数と同じ回数だけ非同期処理自体は行いたい
- イベントを捨てる
flatMapFirst
flatMapLatest
は使えない
- イベントを捨てる
- 処理順を制御するのに適切なoperatorは
concatMap
悪い実装
func doSomething(_ i: Int) -> Single<Int> {
print("start [\(i)]")
return Single<Int>.just(1)
.delay(.seconds(2), scheduler: MainScheduler.instance)
.do(onSuccess: { _ in print("end [\(i)]") })
}
let trigger = PublishRelay<Int>()
_ = trigger
.concatMap { doSomething($0) }
.subscribe()
_ = Observable<Int>
.interval(1, scheduler: MainScheduler.instance)
.bind(to: trigger)
start [0]
end [0]
start [1]
end [1]
start [2]
end [2]
...
start [0]
start [1]
start [2]
end [0]
start [3]
start [4]
end [1]
...
何が悪いか
RxSwiftの concatMap
は、
❌️前のsubsequenceがcompleteするまでsubsequenceを得るselectorの実行を待つ
⭕️selectorによって得られたsubsequenceのsubscribeを待つ
func doSomething(_ i: Int) -> Single<Int> {
+ Single.just(()).flatMap {
print("start [\(i)]")
return Single<Int>.just(1)
.delay(.seconds(2), scheduler: MainScheduler.instance)
.do(onSuccess: { _ in print("end [\(i)]") })
+ }
}
_ = trigger
.concatMap { doSomething($0) }
.subscribe()
start [0]
end [0]
start [1]
end [1]
start [2]
end [2]
...
結論
concatMap
に限った話ではなく、「ストリームを作る」と「ストリームが購読・実行される」のタイミングの違いは意識しましょうねという話に一般化できます。
Author And Source
この問題について(RxSwiftのconcatMapはsubsequenceを得る処理自体を待つわけじゃない), 我々は、より多くの情報をここで見つけました https://qiita.com/takasek/items/d8f9aa121384d44213dc著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .