一、前言
以下場景往往由於事件頻繁被觸發,因而頻繁執行DOM操作、資源加載等重行為,導致UI停頓甚至瀏覽器崩潰。
1. window對象的resize、scroll事件
2. 拖拽時的mousemove事件
3. 射擊游戲中的mousedown、keydown事件
4. 文字輸入、自動完成的keyup事件
實際上對於window的resize事件,實際需求大多為停止改變大小n毫秒后執行后續處理;而其他事件大多的需求是以一定的頻率執行后續處理。針對這兩種需求就出現了debounce和throttle兩種解決辦法。本篇暫且只討論debounce方式
二、什么是debounce
1. 定義
如果用手指一直按住一個彈簧,它將不會彈起直到你松手為止。
也就是說當調用動作n毫秒后,才會執行該動作,若在這n毫秒內又調用此動作則將重新計算執行時間。
方法定義如下
1 /** 2 * 空閑控制 返回函數連續調用時,空閑時間必須大於或等於 idle,action 才會執行 3 * @param fn {Function} 相關執行函數 4 * @param delay {Number} 延遲時間,也就是閾值,單位是毫秒 5 * @return {function} 返回一個“去彈跳”了的函數 6 */ 7 debounce(fn,delay)
2. 簡單實現
1 /** 2 * 3 * @param fn {Function} 實際要執行的函數 4 * @param delay {Number} 延遲時間,也就是閾值,單位是毫秒(ms) 5 * 6 * @return {Function} 返回一個“去彈跳”了的函數 7 */ 8 function debounce(fn, delay) { 9 10 // 定時器,用來 setTimeout 11 var timer 12 13 // 返回一個函數,這個函數會在一個時間區間結束后的 delay 毫秒時執行 fn 函數 14 return function () { 15 16 // 保存函數調用時的上下文和參數,傳遞給 fn 17 var context = this 18 var args = arguments 19 20 // 每次這個返回的函數被調用,就清除定時器,以保證不執行 fn 21 clearTimeout(timer) 22 23 // 當返回的函數被最后一次調用后(也就是用戶停止了某個連續的操作), 24 // 再過 delay 毫秒就執行 fn 25 timer = setTimeout(function () { 26 fn.apply(context, args) 27 }, delay) 28 } 29 }
下面展示效果
一般代碼
一般效果
加上去抖動邏輯后代碼
去抖動后效果