Tru*_*an1 9 grand-central-dispatch debouncing swift swift-concurrency
我有一个现有的防抖实用程序,使用DispatchQueue
. 它接受一个闭包并在达到时间阈值之前执行它。它可以这样使用:
let limiter = Debouncer(limit: 5)
var value = ""
func sendToServer() {
limiter.execute {
print("\(Date.now.timeIntervalSince1970): Fire! \(value)")
}
}
value.append("h")
sendToServer() // Waits until 5 seconds
value.append("e")
sendToServer() // Waits until 5 seconds
value.append("l")
sendToServer() // Waits until 5 seconds
value.append("l")
sendToServer() // Waits until 5 seconds
value.append("o")
sendToServer() // Waits until 5 seconds
print("\(Date.now.timeIntervalSince1970): Last operation called")
// 1635691696.482115: Last operation called
// 1635691701.859087: Fire! hello
Run Code Online (Sandbox Code Playgroud)
请注意,它不是Fire!
多次调用,而是在最后一次使用上一个任务的值后仅 5 秒调用。该Debouncer
实例配置为将队列中的最后一个任务保留 5 秒,无论调用多少次。闭包被传递到execute(block:)
方法中:
final class Debouncer {
private let limit: TimeInterval
private let queue: DispatchQueue
private var workItem: DispatchWorkItem?
private let syncQueue = DispatchQueue(label: "Debouncer", attributes: [])
init(limit: TimeInterval, queue: DispatchQueue = .main) {
self.limit = limit
self.queue = queue
}
@objc func execute(block: @escaping () -> Void) {
syncQueue.async { [weak self] in
if let workItem = self?.workItem {
workItem.cancel()
self?.workItem = nil
}
guard let queue = self?.queue, let limit = self?.limit else { return }
let workItem = DispatchWorkItem(block: block)
queue.asyncAfter(deadline: .now() + limit, execute: workItem)
self?.workItem = workItem
}
}
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能将其转换为并发操作,以便可以像下面这样调用它:
let limit = Debouncer(limit: 5)
func sendToServer() {
await limiter.waitUntilFinished
print("\(Date.now.timeIntervalSince1970): Fire! \(value)")
}
sendToServer()
sendToServer()
sendToServer()
Run Code Online (Sandbox Code Playgroud)
但是,这不会使任务反跳,而是将其挂起,直到调用下一个任务为止。相反,它应该取消先前的任务并保留当前任务直到去抖时间。这可以通过Swift Concurrency来完成吗?还是有更好的方法来做到这一点?
Rob*_*Rob 16
任务可以使用isCancelled
or checkCancellation
,但是为了防反跳例程,您想要等待一段时间,您可能只使用 的抛出再现Task.sleep(nanoseconds:)
,其文档说:
\n\n如果任务在时间结束之前被取消,该函数将抛出
\nCancellationError
。
因此,这有效地消除了 2 秒的抖动。
\nvar task: Task<(), Never>?\n\nfunc debounced(_ string: String) {\n task?.cancel()\n\n task = Task {\n do {\n try await Task.sleep(nanoseconds: 2_000_000_000)\n logger.log("result \\(string)")\n } catch {\n logger.log("canceled \\(string)")\n }\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n注意,Apple\xe2\x80\x99sswift-async-algorithms
有一个debounce
for 异步序列。
归档时间: |
|
查看次数: |
2902 次 |
最近记录: |