Skip to content

Instantly share code, notes, and snippets.

@boraseoksoon
Last active June 13, 2023 20:08
Show Gist options
  • Save boraseoksoon/32177a677d8a8549096049a17e10572f to your computer and use it in GitHub Desktop.
Save boraseoksoon/32177a677d8a8549096049a17e10572f to your computer and use it in GitHub Desktop.
Throttle function to be able to guarantee first and last operations.
enum TaskType {
case current
case main
}
enum ThrottleType {
case none
case immediateFirst
case guaranteeLast
case both
}
var lastThrottleDate: Date?
var debounceTimer: Timer?
var operations = [(() -> Void)]()
func throttle(
_ interval: Duration = .seconds(1),
on taskType: TaskType = .main,
type: ThrottleType = .none,
operation: @escaping () -> Void
) {
let now = Date()
let timeInterval = TimeInterval(interval.components.seconds) + Double(interval.components.attoseconds)/1e18
let isThrottlingPeriod = lastThrottleDate != nil && now.timeIntervalSince(lastThrottleDate!) < timeInterval
let debounceInterval = {
let debounceFactor: Double = 1.1
return timeInterval * debounceFactor
}()
let operation = {
Task { taskType == .main ? await MainActor.run { operation() } : operation() }
lastThrottleDate = now
}
let debounce = {
debounceTimer?.invalidate()
debounceTimer = Timer.scheduledTimer(withTimeInterval: debounceInterval, repeats: false) { _ in
operation()
}
}
lazy var canRun = lastThrottleDate == nil || !isThrottlingPeriod
switch type {
case .none:
if !isThrottlingPeriod {
operation()
}
case .immediateFirst:
if canRun {
operation()
}
case .guaranteeLast:
isThrottlingPeriod ? debounce() : operation()
case .both:
canRun ? operation() : debounce()
}
}
/// you can use it like this
/*
throttle(type: .both) {
search(text: text)
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment