@@ -33,14 +33,15 @@ public actor Debouncer<Parameter> {
33
33
private let makeCall : ( Parameter ) async -> Void
34
34
35
35
/// In the time between the call to `scheduleCall` and the call actually being committed (ie. in the time that the
36
- /// call can be debounced), the task that would commit the call (unless cancelled) and the parameter with which this
37
- /// call should be made.
38
- private var inProgressData : ( Parameter , Task < Void , Never > ) ?
36
+ /// call can be debounced), the task that would commit the call (unless cancelled), the parameter with which this
37
+ /// call should be made and the time at which the call should be made. Keeping track of the time ensures that we don't
38
+ /// indefinitely debounce if a new `scheduleCall` is made every 0.4s but we debounce for 0.5s.
39
+ private var inProgressData : ( Parameter , ContinuousClock . Instant , Task < Void , Never > ) ?
39
40
40
41
public init (
41
42
debounceDuration: Duration ,
42
43
combineResults: @escaping ( Parameter , Parameter ) -> Parameter ,
43
- _ makeCall: @escaping ( Parameter ) async -> Void
44
+ _ makeCall: @Sendable @ escaping ( Parameter) async -> Void
44
45
) {
45
46
self . debounceDuration = debounceDuration
46
47
self . combineParameters = combineResults
@@ -52,26 +53,28 @@ public actor Debouncer<Parameter> {
52
53
/// `debounceDuration` after the second `scheduleCall` call.
53
54
public func scheduleCall( _ parameter: Parameter ) {
54
55
var parameter = parameter
55
- if let ( inProgressParameter, inProgressTask) = inProgressData {
56
+ var targetDate = ContinuousClock . now + debounceDuration
57
+ if let ( inProgressParameter, inProgressTargetDate, inProgressTask) = inProgressData {
56
58
inProgressTask. cancel ( )
57
59
parameter = combineParameters ( inProgressParameter, parameter)
60
+ targetDate = inProgressTargetDate
58
61
}
59
62
let task = Task {
60
63
do {
61
- try await Task . sleep ( for : debounceDuration )
64
+ try await Task . sleep ( until : targetDate )
62
65
try Task . checkCancellation ( )
63
66
} catch {
64
67
return
65
68
}
66
69
inProgressData = nil
67
70
await makeCall ( parameter)
68
71
}
69
- inProgressData = ( parameter, task)
72
+ inProgressData = ( parameter, ContinuousClock . now + debounceDuration , task)
70
73
}
71
74
}
72
75
73
76
extension Debouncer < Void > {
74
- public init ( debounceDuration: Duration , _ makeCall: @escaping ( ) async -> Void ) {
77
+ public init ( debounceDuration: Duration , _ makeCall: @Sendable @ escaping ( ) async -> Void ) {
75
78
self . init ( debounceDuration: debounceDuration, combineResults: { _, _ in } , makeCall)
76
79
}
77
80
0 commit comments