Combine

debounce 와 throttle

chaneeii 2022. 11. 3. 09:57

debounce

공식문서는 debounce가

이벤트 간 특정한 시간간격이 지난 후 elements를 publish 한다고 설명합니다.

 

 

공식문서에서는 다음과 같이 debounce 에 대해 설명하고 있습니다!

  • debounce operator를 사용하면 업스트림 publisher 로부터 value의 전송 간격과 value 의 개수를 제어할 수 있다.
  • 이 operator 는 다운스트림에 전달되는 값의 수를 지정한 속도로 줄여야하는 bursty 혹은 대량 이벤트 스트림을 처리하는데 유용하다.

 

저는 이번에 검색기능을 구현하면서 요 기능을 찾아보게 되었어요!

textfield 에 값을 입력할때마다 api call 을 하면 불필요하고 너무 많은 api 를 요청하게 되기 때문에 일정 시간을 두고 검색을 하려고 해요! 성능은 중요하니깐..+ 서버비용,,,,!

 

debounce 특징

  • 입력주기가 끝나면 마지막 값을 출력한다
  • 추가로 value 가 들어오면 주기가 다시 갱신된다

공식문서에 예제로 함께 보면,

/* DEBOUNCE */

let bounces:[(Int,TimeInterval)] = [
    (0, 0),
    (1, 0.25),  // 0.25s interval since last index
    (2, 1),     // 0.75s interval since last index
    (3, 1.25),  // 0.25s interval since last index
    (4, 1.5),   // 0.25s interval since last index
    (5, 2)      // 0.5s interval since last index
]

let subject = PassthroughSubject<Int, Never>()
let cancellable = subject
    .debounce(for: .seconds(0.5), scheduler: RunLoop.main)
    .sink { index in
        print ("Received index \\(index)")
    }

for bounce in bounces {
    DispatchQueue.main.asyncAfter(deadline: .now() + bounce.1) {
        subject.send(bounce.0)
    }
}

마블다이어그램으로 그림과 같이 나타낼 수 있습니다.

 

보라색 시점에 값이 방출되고,

추가로 value 가 들어오면 이 주기는 다시 갱신이 되고

노란색은 값이 출력되기 전 실행되는 주기입니다! (0.5)

노란색이 끝나는 시점에서 마지막 값이 downstream 으로 가게 됩니다

 

 

throttle

throttle 도 먼저 공식문서를 보도록 할게요

throttle 은 특정시간 간격안에서 업스트립 publisher가 publish한 가장 최근의 값 or 첫번째 element 를 publish 합니다

 

그래서 그런지 인자중에 latest: Bool 이 있더라구요

 

 

공식문서에서는 추가로 설명하는 부분이 있는데

  • throttle 을 사용해서 사용자가 특정한 간격 동안 upstream publisher 로 부터 선택적으로 다시 publish 할수있다는 것이다..? (뭔소리죠,,?)
  • throttling 간격동안 upstream 에서 받은 다른 elements 는 다시 publish 되지 않는다

라고 설명하는데 이해가 잘 안가서 찾아보다가 felix-ios 블로그의 글을 보고 이해했습니다.

https://felix-mr.tistory.com/10

 

throttle 은 가장 최근의 값 혹은 첫번째 값 만을 publish 하기 때문에

  • 첫번째 값일 경우 : 시간이 경과되기 전까지 첫번째 이후에 업스트림으로 부터 publish 된 값들을 무시
  • 가장 최근 값의 경우 : 시간이 경과되기 전 시점에서 자미작 요소 이전에 업스트림으로부터 publish 된 값들은 무시

라는 당연한 소리였어요,,,

너무 말이 어려웠습니다 🥹

 

 

throttle 특징

  • 처음 구독 시점에 첫번째 value를 바로 한번 방출합니다
  • 첫번째값인 경우 (latest: false) : 특정 주기 안의 첫번째 value 를 출력
  • 가장 최근값인 경우 (latest: true) : 특정 주기 안의 가장 최근value 출력

 

요건 버튼 여러번 터치할때 처음 터치만 받고 일정 간격지나고 보내게 한다면 좋을 것 같아요!

아래 예제는 latest 가 true인 경우에요!

/* THROTTLE */

let cancellable = Timer.publish(every: 3.0, on: .main, in: .default)
    .autoconnect()
    .print("➡️\\(Date().description)")
    .throttle(for: 10.0, scheduler: RunLoop.main, latest: true)
    .sink(
        receiveCompletion: { print ("🔥Completion: \\($0).") },
        receiveValue: { print("✅ Received Timestamp \\($0).") }
     )

디버깅 창을 보면 요렇게 나와요

 

그림으로 한번 그려봤습니다

 

 

false 로 바꿨을때는, 즉 첫번째를 내보내는 경우는

아래와 같은 결과가 나옵니다!

 

보면 첫번째 값이 received timestamp 로 찍힌걸 볼 수 있죠??

 

 

 

 

요기까지 debounce 와 throttle 에 대해 알아봤습니다!

 

 

 

References

Combine) debounce와 throttle의 차이

[Combine 책 정리] Chapter 6: Time Manipulation Operators

Throttle 와 Debounce 개념 정리하기

Apple Developer Documentation