防抖的作用
業(yè)務如下: 假如我們是一個CDN服務商, 向用戶提供了刷新某url緩存的功能, 假如有用戶一直刷新某一個url的緩存, 而緩存是一個耗時操作(需要通知很多異地節(jié)點更新), 這可能會導致系統(tǒng)卡頓.
如何解決這個問題?
你可能會說, 這不就是簡單的限流問題嗎, 使用Nginx limit_req_zone指令即可實現(xiàn).
但熟悉"節(jié)流"和"防抖"的人就能發(fā)現(xiàn)問題:
節(jié)流可能導致用戶最后一次請求被丟棄, 在CDN刷新緩存業(yè)務中就會導致用戶刷新了緩存, 可url沒有被更新為最新文件.
而防抖保證最后一次請求一定會被執(zhí)行, 并丟棄中間的請求, 這符合我們的業(yè)務需求, 即: 將CDN中url更新為用戶最后一次上傳的文件, 同時也能限制速率.
Nginx顯然不提供防抖功能, 只有自己在業(yè)務代碼中實現(xiàn)了.
防抖多用于前端, 如在Lodash庫中就有它的實現(xiàn).
它的代碼像這樣:
function debounce(fn, interval) {
let timeout = null;
return function() {
clearInterval(timeout);
timeout = setTimeout(() => {
fn.apply(this, arguments)
}, 500);
}
}
使用它
let f = debounce(function(i){console.log("dododo", i)}, 1000)
f(1)
f(2)
只會打印出dododo 2
在Golang中可以參考此實現(xiàn), 將setTimeout
換成time.AfterFunc
即可
使用Golang寫防抖
package debounce
import (
"sync"
"time"
)
func New(interval time.Duration) func(f func()) {
var l sync.Mutex
var timer *time.Timer
return func(f func()) {
l.Lock()
defer l.Unlock()
// 使用lock保證d.timer更新之前一定先Stop.
if timer != nil {
timer.Stop()
}
timer = time.AfterFunc(interval, f)
}
}
使用它
d := New(1 * time.Second)
d(func() {
println("do 1", time.Now().String())
})
d(func() {
println("do 2", time.Now().String())
})
代碼很簡單, 值得注意的是和單線程的javascript不同, golang中需要用鎖來達到并發(fā)安全.