Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Debounce + Throttle
import Dispatch
private var throttleWorkItems = [AnyHashable: DispatchWorkItem]()
private var lastDebounceCallTimes = [AnyHashable: DispatchTime]()
private let nilContext: AnyHashable = arc4random()
public extension DispatchQueue {
/**
- parameters:
- deadline: The timespan to delay a closure execution
- context: The context in which the throttle should be executed
- action: The closure to be executed
Delays a closure execution and ensures no other executions are made during deadline
*/
public func throttle(deadline: DispatchTime, context: AnyHashable? = nil, action: @escaping () -> Void) {
let worker = DispatchWorkItem {
defer { throttleWorkItems.removeValue(forKey: context ?? nilContext) }
action()
}
asyncAfter(deadline: deadline, execute: worker)
throttleWorkItems[context ?? nilContext]?.cancel()
throttleWorkItems[context ?? nilContext] = worker
}
/**
- parameters:
- interval: The interval in which new calls will be ignored
- context: The context in which the debounce should be executed
- action: The closure to be executed
Executes a closure and ensures no other executions will be made during the interval.
*/
public func debounce(interval: Double, context: AnyHashable? = nil, action: @escaping () -> Void) {
if let last = lastDebounceCallTimes[context ?? nilContext], last + interval > .now() {
return
}
lastDebounceCallTimes[context ?? nilContext] = .now()
async(execute: action)
// Cleanup & release context
throttle(deadline: .now() + interval) {
lastDebounceCallTimes.removeValue(forKey: context ?? nilContext)
}
}
}
@edvinassabaliauskas
Copy link

edvinassabaliauskas commented Sep 21, 2021

Hey 👋, quite a neat solution!
But I see few issues:

  1. Default context (nilContext) is same for different dispatch queues which gives quite unexpected behaviour. Default context could simply be a queue label.
  2. Global vars are not thread-safe. Issue could easily arise when throttling/debouncing actions from DispatchQueue.global().
  3. You also mixed throttle with debounce and vice versa.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment