函數節流之debounce
阿新 • • 發佈:2018-07-18
ext 一次 時間 times function 拖拽 進行 let 序列
瀏覽器中某些計算和處理要比其他的昂貴很多。例如, DOM 操作比起非 DOM 交互需要更多的內存和 CPU 時間。連續嘗試進行過多的 DOM 相關操作可能會導致瀏覽器掛起,有時候甚至會崩潰。尤其在 IE 中使用 onresize 事件處理程序的時候容易發生,當調整瀏覽器大小的時候,該事件會連續觸發。在 onresize 事件處理程序內部如果嘗試進行 DOM 操作,其高頻率的更改可能會讓瀏覽器崩潰。為了繞開這個問題,你可以使用定時器對該函數進行節流。
函數節流背後的基本思想是指,某些代碼不可以在沒有間斷的情況連續重復執行。第一次調用函數,創建一個定時器,在指定的時間間隔之後運行代碼。當第二次調用該函數時,它會清除前一次的定時器並設置另一個 (摘錄至JavaScript高級程序設計的函數節流)。
適用的應用場景:
1、window對象的resize、scroll事件
2、拖拽時的mousemove事件
3、射擊遊戲中的mousedown、keydown事件
4、文字輸入、自動完成的keyup事件
1 /** 2 * 函數去抖,保證在一段時間內,被調用函數只是執行一次 3 * @param {*} func 調用用的函數,function 4 * @param {*} wait 等待的時間,單位ms 5 * @param {*} immediate 當immediate為true時,第一次調用該函數的時候,就調用func函數;false表示超時之後再調用 6 */7 export function debounce (func, wait, immediate = false) { 8 let timeout, args, context, timestamp, result 9 10 const later = function () { 11 // 記錄上一次觸發時間間隔 12 const last = +new Date() - timestamp 13 14 // 上次被包裝函數被調用時間間隔last小於設定時間間隔wait 15 // 調用的時間比較頻繁,重新計算下次執行的時間 16 if (last < wait && last > 0) {17 timeout = setTimeout(later, wait - last) 18 } else { 19 timeout = null 20 // 如果設定為immediate===true,因為開始邊界已經調用過了此處無需調用 21 if (!immediate) { 22 result = func.apply(context, args) 23 if (!timeout) context = args = null 24 } 25 } 26 } 27 28 // ...args:使用es6的rest運算符,把逗號隔開的值序列組合成一個數組:如test(1,2,3,4) ==> args:[1,2,3,4] 29 // 符合apply(obj,[]) 30 return function (...args) { 31 // 把上下文的this對象保存下來,因為下面的apply要使用 32 context = this 33 // 記錄當前的時間戳,也可以使用Date.now() 34 timestamp = +new Date() 35 // 第一次調用該方法時,且immediate為true,則調用func函數 36 const callNow = immediate && !timeout 37 // 如果延時不存在,重新設定延時,首次的時候 38 if (!timeout) { 39 timeout = setTimeout(later, wait) 40 } 41 // 如果immediate為true,那麽立馬調用該函數 42 if (callNow) { 43 result = func.apply(context, args) 44 context = args = null 45 } 46 47 return result 48 } 49 }
函數節流之debounce