Last active
September 23, 2021 07:25
-
-
Save fjcaetano/ff3e994c4edb4991ab8280f34994beb4 to your computer and use it in GitHub Desktop.
Debounce + Throttle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey 👋, quite a neat solution!
But I see few issues:
nilContext
) is same for different dispatch queues which gives quite unexpected behaviour. Default context could simply be a queuelabel
.var
s are not thread-safe. Issue could easily arise when throttling/debouncing actions fromDispatchQueue.global()
.