How can I debounce a method call?

前端 未结 13 1522
醉梦人生
醉梦人生 2020-11-30 01:18

I\'m trying to use a UISearchView to query google places. In doing so, on text change calls for my UISearchBar, I\'m making a request to google pla

13条回答
  •  情深已故
    2020-11-30 01:46

    Swift 3 version

    1. Basic debounce function

    func debounce(interval: Int, queue: DispatchQueue, action: @escaping (() -> Void)) -> () -> Void {
        var lastFireTime = DispatchTime.now()
        let dispatchDelay = DispatchTimeInterval.milliseconds(interval)
    
        return {
            lastFireTime = DispatchTime.now()
            let dispatchTime: DispatchTime = DispatchTime.now() + dispatchDelay
    
            queue.asyncAfter(deadline: dispatchTime) {
                let when: DispatchTime = lastFireTime + dispatchDelay
                let now = DispatchTime.now()
                if now.rawValue >= when.rawValue {
                    action()
                }
            }
        }
    }
    

    2. Parameterized debounce function

    Sometimes it's useful to be have the debounce function take a parameter.

    typealias Debounce = (_ : T) -> Void
    
    func debounce(interval: Int, queue: DispatchQueue, action: @escaping Debounce) -> Debounce {
        var lastFireTime = DispatchTime.now()
        let dispatchDelay = DispatchTimeInterval.milliseconds(interval)
    
        return { param in
            lastFireTime = DispatchTime.now()
            let dispatchTime: DispatchTime = DispatchTime.now() + dispatchDelay
    
            queue.asyncAfter(deadline: dispatchTime) {
                let when: DispatchTime = lastFireTime + dispatchDelay
                let now = DispatchTime.now()
    
                if now.rawValue >= when.rawValue {
                    action(param)
                }
            }
        }
    }
    

    3. Example

    In the following example you can see, how the debouncing works, using a string parameter to identify the calls.

    let debouncedFunction = debounce(interval: 200, queue: DispatchQueue.main, action: { (identifier: String) in
        print("called: \(identifier)")
    })
    
    DispatchQueue.global(qos: .background).async {
        debouncedFunction("1")
        usleep(100 * 1000)
        debouncedFunction("2")
        usleep(100 * 1000)
        debouncedFunction("3")
        usleep(100 * 1000)
        debouncedFunction("4")
        usleep(300 * 1000) // waiting a bit longer than the interval
        debouncedFunction("5")
        usleep(100 * 1000)
        debouncedFunction("6")
        usleep(100 * 1000)
        debouncedFunction("7")
        usleep(300 * 1000) // waiting a bit longer than the interval
        debouncedFunction("8")
        usleep(100 * 1000)
        debouncedFunction("9")
        usleep(100 * 1000)
        debouncedFunction("10")
        usleep(100 * 1000)
        debouncedFunction("11")
        usleep(100 * 1000)
        debouncedFunction("12")
    }
    

    Note: The usleep() function is only used for demo purposes and may not be the most elegant solution for a real app.

    Result

    You always get a callback, when there is an interval of at least 200ms since the last call.

    called: 4
    called: 7
    called: 12

提交回复
热议问题