Skip to content

Commit 0feaff7

Browse files
authored
Merge pull request #275 from leontedev/master
Adds latest parameter for throttle
2 parents 9821826 + 3ba9556 commit 0feaff7

File tree

1 file changed

+58
-31
lines changed

1 file changed

+58
-31
lines changed

Sources/SignalProtocol+Filtering.swift

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -374,44 +374,71 @@ extension SignalProtocol {
374374
}
375375
}
376376

377-
/// Throttle the signal to emit at most one element per given `seconds` interval. Signal will emit latest element from each interval.
377+
/// Throttle the signal to emit at most one element per given `seconds` interval. Emits either the most-recent or first element in the specified time interval.
378+
///
379+
/// - parameter seconds: The interval at which to find and emit either the most recent or the first element.
380+
/// - parameter latest: Defaults to `true`. A Bool value that indicates whether to publish the most recent element. If `false`, it emits the first element received during the interval. If `true` Signal will emit latest element from each interval.
378381
///
379382
/// Check out interactive example at [https://rxmarbles.com/#throttle](https://rxmarbles.com/#throttle)
380-
public func throttle(for seconds: Double, queue: DispatchQueue = DispatchQueue(label: "com.reactive_kit.signal.throttle")) -> Signal<Element, Error> {
381-
return Signal { observer in
382-
var isInitialElement = true
383-
var throttledDisposable: Disposable? = nil
384-
var lastElement: Element? = nil
385-
var isFinished: Bool = false
386-
return self.observe { event in
387-
queue.async {
388-
switch event {
389-
case .next(let element):
390-
if isInitialElement {
391-
isInitialElement = false
392-
observer.receive(element)
393-
} else {
394-
lastElement = element
395-
}
396-
guard throttledDisposable == nil else { return }
397-
throttledDisposable = queue.disposableAfter(when: seconds) {
398-
if let element = lastElement {
383+
public func throttle(
384+
for seconds: Double,
385+
queue: DispatchQueue = DispatchQueue(label: "com.reactive_kit.signal.throttle"),
386+
latest: Bool = true
387+
) -> Signal<Element, Error> {
388+
if latest {
389+
return Signal { observer in
390+
var isInitialElement = true
391+
var throttledDisposable: Disposable? = nil
392+
var lastElement: Element? = nil
393+
var isFinished: Bool = false
394+
return self.observe { event in
395+
queue.async {
396+
switch event {
397+
case .next(let element):
398+
if isInitialElement {
399+
isInitialElement = false
399400
observer.receive(element)
400-
lastElement = nil
401+
} else {
402+
lastElement = element
401403
}
402-
if isFinished {
403-
observer.receive(completion: .finished)
404+
guard throttledDisposable == nil else { return }
405+
throttledDisposable = queue.disposableAfter(when: seconds) {
406+
if let element = lastElement {
407+
observer.receive(element)
408+
lastElement = nil
409+
}
410+
if isFinished {
411+
observer.receive(completion: .finished)
412+
}
413+
throttledDisposable = nil
404414
}
405-
throttledDisposable = nil
415+
case .failed(let error):
416+
observer.receive(completion: .failure(error))
417+
case .completed:
418+
guard throttledDisposable == nil else {
419+
isFinished = true
420+
return
421+
}
422+
observer.receive(completion: .finished)
406423
}
407-
case .failed(let error):
408-
observer.receive(completion: .failure(error))
409-
case .completed:
410-
guard throttledDisposable == nil else {
411-
isFinished = true
412-
return
424+
}
425+
}
426+
}
427+
} else {
428+
return Signal { observer in
429+
let lock = NSRecursiveLock(name: "com.reactive_kit.signal.throttle")
430+
var _lastEventTime: DispatchTime?
431+
return self.observe { event in
432+
switch event {
433+
case .next(let element):
434+
lock.lock(); defer { lock.unlock() }
435+
let now = DispatchTime.now()
436+
if _lastEventTime == nil || now.rawValue > (_lastEventTime! + seconds).rawValue {
437+
_lastEventTime = now
438+
observer.receive(element)
413439
}
414-
observer.receive(completion: .finished)
440+
default:
441+
observer.on(event)
415442
}
416443
}
417444
}

0 commit comments

Comments
 (0)