通常在項目中咱們會對input、scroll、resize等事件進行節流控制,防止事件過多觸發,減小資源消耗;在vue的官網的例子中就有關於lodash的debounce方法的使用,當時也提到了throttle,但一直沒搞明白節流 throttle 與 去抖 debounce具體區別在哪裏,因此花了點時間來搞清楚。css
節流 throttle 與 去抖 debounce的區別主要在觸發時機上:html
debounce(func, wait, options)
:建立並返回函數的防反跳版本,將延遲函數的執行(真正的執行)在函數最後一次調用時刻的wait毫秒以後,對於必須在一些輸入(可能是一些用戶操做)中止以後再執行的行爲有幫助。將一個連續的調用歸爲一個,若是連續在wait毫秒內調用,最後只有最後一次會執行throttle(func, wait, options)
:建立並返回一個像節流閥同樣的函數,當重複調用函數的時候,最多每隔指定的wait毫秒調用一次該函數;不容許方法在每wait毫秒間執行超過一次,若是連續在wait毫秒內調用,最後執行會均勻分佈在大約每wait一次對於lodash來講,throttle是調用debounce來實現的,throttle 和 debounce 最終都會都會調用 debounce 方法。當調用 _.debounce
lodash會返回一個函數,這個函數在被調用時會生成一個 setTimeout(delayed, delay)。其中 delayed 又是一個內部方法,在 delayed 被調用時進行以下檢測:當前時間 - 上次func被調用事件 是否 小於 0 或 大於 delay ?若是是則執行一次 func,記錄並返回執行結果,同時更新上次被調用時間;若是不是則調用 setTimeout 進行下一次的判斷。_.throttle
方法只不過是多給 debounce 傳了一個 options = {maxWait: $maxWait, leading: true, trailing: true}
,這個選項的意思是至少保證在每 maxWait 時間讓 func 被調用一次。前端
能夠看下面的栗子:vue
這個圖中圖中每一個小格大約30ms,右邊有原生mouseover事件、lodash與jQuery節流去抖插件的debounce與throttle事件。
在圖左區域移動鼠標時:對於debounce,mouseover事件一直沒有被調用,直到停下來才被調用一次。而throttle是每wait毫秒就調用一次。jquery
debounce:第一次觸發後,進行倒計wait毫秒,若是倒計時過程當中有其餘觸發,則重置倒計時;不然執行。用它來丟棄一些重複的密集操做,直到流量減慢。
throttle:第一次觸發後先執行fn(lodash能夠經過{leading: false}
來取消),而後wait ms後再次執行,在單位wait毫秒內的全部重複觸發都被拋棄。即若是有接二連三的觸發,每wait ms執行fn一次,用在每隔必定間隔執行回調的場景。ajax
按照上面的說明,去抖就是連續屢次delay內的操做取最後一次操做真正執行。微信
let reduceEvent function debounce(cb, delay) { if (!reduceEvent) { reduceEvent = setTimeout(() => { cb() console.log('執行啦!!') reduceEvent = null }, delay) } } setTimeout(() => debounce(() => console.log(1), 2000), 1000) // 打印: 1 執行啦!! setTimeout(() => debounce(() => console.log(2), 2000), 2000) setTimeout(() => debounce(() => console.log(3), 2000), 2000) setTimeout(() => debounce(() => console.log(4), 2000), 4000) // 打印: 4 執行啦!!
按照上面的說明,節流就是連續屢次delay內的操做按照指定的間隔來執行。app
function throttle(func, wait = 200) { let last = 1 let timer return function(...rest) { const now = +new Date() if (last && now - last < wait) { clearTimeout(timer) timer = setTimeout(() => { last = now func.apply(this, rest) }, wait) } else { last = now func.apply(this, rest) clearTimeout(timer) } } } const task = throttle(() => console.log(1), 2000) setTimeout(task, 0) setTimeout(task, 500) setTimeout(task, 1000) setTimeout(task, 2000) // 打印: 1 1
網上的帖子大多深淺不一,甚至有些先後矛盾,在下的文章都是學習過程當中的總結,若是發現錯誤,歡迎留言指出~ide
參考:函數
PS:歡迎你們關注個人公衆號【前端下午茶】,一塊兒加油吧~
另外能夠加入「前端下午茶交流羣」微信羣,長按識別下面二維碼便可加我好友,備註加羣,我拉你入羣~