先看看概念
函數防抖(debounce):
在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時;典型的案例就是輸入搜索:輸入結束后n秒才進行搜索請求,n秒內又輸入的內容,就重新計時。
應用場景:
- search搜索聯想,用戶在不斷輸入值時,用防抖來節約請求資源。
- window觸發resize的時候,不斷的調整瀏覽器窗口大小會不斷的觸發這個事件,用防抖來讓其只觸發一次
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="btn">第一次點擊按鈕立即執行 接下來 防抖</button> <button id="btn2">終止</button> </body> <script> var btn = document.getElementById('btn'); let b= 2 let f = debounce_2(sayHi,2000,true) btn.addEventListener('click',()=>{ f(b) }) btn2.addEventListener('click',()=>{ f.stop() }) // 防抖(非立即執行) function debounce_1(fn,wait){ let timer = null; return function(){ clearTimeout(timer); timer = setTimeout(() => { fn.apply(this,arguments) },wait) } } // 防抖立即執行 function debounce_2(fn,wait){ let time = null let flag = true return function (){ clearTimeout(time) if(flag){ fn.apply(this,arguments) flag = false } time = setTimeout(()=>{ flag = true },wait) } } // 防抖自定義第一次是否執行 function debounce_3(fn,wait,isImmediate = true){ let flag = true let time = null if(isImmediate){ if(flag){ return function (){ fn.apply(this,arguments) flag = false } } clearTimeout(time) time = setTimeout(()=>{ flag = true },wait) } return function (){ clearTimeout(time); time = setTimeout(() => { fn.apply(this,arguments) },wait) } } // 防抖自定義第一次是否執行 且可中斷執行 function debounce_4(fn, wait = 500, isImmediate = false) { // 計時器 let timerId = null; // flag為真時立即執行 let flag = true; let resultFunc = null; if (isImmediate) { // 立即執行 // 例如:用戶在輸入框中輸入字符,輸入第一個字符時,立即執行一次 // 之后,最終間隔超過2秒后,才執行補全查詢 resultFunc = function () { let context = this; clearTimeout(timerId); if (flag) { fn.apply(context, arguments); flag = false } timerId = setTimeout(() => { flag = true }, wait) } resultFunc.cancel = function () { // 例如,用戶打字很快,然后輸入完成后,未達到兩秒鍾就移動鼠標 // 此時輸入框失去焦點,觸發取消等待方法,立刻執行補全查詢操作並顯示結果出來 console.log("立即取消等待") clearTimeout(timerId); flag = true; } } else { // 不立即執行 // 例如:用戶在輸入框中輸入字符,最終間隔超過2秒后,才執行補全查詢 resultFunc = function () { let context = this; clearTimeout(timerId); timerId = setTimeout(() => { fn.apply(context, arguments) }, wait) } resultFunc.cancel = function () { console.log("立即取消等待"); clearTimeout(timerId); } } return resultFunc; } function sayHi(b) { console.log(b) console.log('防抖') } </script> </html>
函數節流(throttle):
規定在一個單位時間內,只能觸發一次函數,如果這個單位時間內觸發多次函數,只有一次生效; 典型的案例就是鼠標不斷點擊觸發,規定在n秒內多次點擊只有一次生效。
應用場景:
- 鼠標不斷點擊觸發,mousedown(單位時間內只觸發一次)
- 監聽滾動事件,比如是否滑到底部自動加載更多,用throttle來判斷
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="btn">第一次點擊按鈕立即執行 接下來 節流</button> <button id="btn2">終止</button> </body> <script> var btn = document.getElementById('btn'); let b= 2 let f = throttle_4(sayHi,3000) btn.addEventListener('click',()=>{ f(b) // throttle_3(sayHi,3000)(b) 不能這么寫,因為這相當於每次都重新聲明了這個節流函數 }) btn2.addEventListener('click',()=>{ f.stop() }) //節流(非立即執行) function throttle_1(fn,wait){ let flag = true; return function(){ if(flag == true){ flag = false var timer = setTimeout(() => { fn.apply(this,arguments) flag = true },wait) } } } //節流(立即執行) function throttle_2(fn,wait){ var flag = true; var timer = null; return function(){ if(flag) { fn.apply(this,arguments); flag = false; timer = setTimeout(() => { flag = true },wait) } } } //節流(自定義是否立即執行) function throttle_3(fn,wait = 500,isImmediate = false){ let flag = true; let timer = null; if(isImmediate){ return function(){ if(flag) { fn.apply(this,arguments); flag = false; timer = setTimeout(() => { flag = true },wait) } } } return function(){ if(flag == true){ flag = false var timer = setTimeout(() => { fn.apply(this,arguments) flag = true },wait) } } } //節流(自定義是否立即執行且可以中斷) function throttle_4(fn, wait = 500, isImmediate = false) { let flag = true; let timer = null; let resultFunc = null; if (isImmediate) { // 立即執行 resultFunc = function () { if (flag) { fn.apply(this, arguments); flag = false; timer = setTimeout(() => { flag = true }, wait) } } resultFunc.cancel = function () { console.log("立即取消等待") clearTimeout(timer) } } else { // 不立即執行 resultFunc = function () { if (flag == true) { flag = false timer = setTimeout(() => { fn.apply(this, arguments) flag = true }, wait) } } resultFunc.cancel = function () { console.log("立即取消等待") clearTimeout(timer); flag = true; } } return resultFunc; } function sayHi(b) { console.log(b) console.log('節流') } </script> </html>