函式節流(throttle)
函式節流:在指定的間隔時間內只執行一次
有個需要頻繁觸發函式,出於優化效能角度,在規定時間內,只讓函式觸發的第一次生效,後面不生效。
比如下面的例子,在不加函式節流的時候,每當滾動條滾動的時候都會觸發一次,造成大量的效能浪費
// 未新增節流函式
document.onscroll = function () {
console.log('scroll事件被觸發了')
}
新增了節流函式後
// 新增了節流函式
document.onscroll = throttle(function () {
console.log('scroll事件被觸發了')
}, 300)
具體程式碼實現
/**
* @description 函式節流
* @param {Function} fn 需要執行函式節流的函式
* @param {Number} interval 指定間隔時間
*/
function throttle(fn, interval = 300) {
let canRun = true // 通過閉包儲存一個標記
return function () {
if (!canRun) return // 第一次呼叫執行
canRun = false // setTimeout未執行時,後續fn函式呼叫都不會再執行
// setTimeout 定時器延時執行
setTimeout(() => {
fn.apply(this, arguments)
canRun = true // 標記為true,節流完成
}, interval)
}
}
程式碼解釋
簡單來說,函式的節流就是通過閉包儲存一個標記(canRun = true
), 在函式的開頭判斷這個標記是否為true
,如果這個標記為true
的話就繼續執行,否則就return
掉,判斷完標記後立即把這個標記設定為false
,然後把外部傳入的函式的執行包在一個setTimout
中,最後在定時器執行完畢之後再把標記設定為true
,表示本次延遲執行完畢,可以執行下一次迴圈了。當定時器還未執行完畢的時候,canRun
這個標記始終未false
,故在開頭的判斷中總是被return
掉,函式並未執行。、
應用場景
監聽滾動事件判斷是否到頁面底部自動載入更多:給 scroll 加了 debounce 後,只有使用者停止滾動後,才會判斷是否到了頁面底部;如果是 throttle 的話,只要頁面滾動就會間隔一段時間判斷一次等
函式防抖(debounce)
函式防抖: 一個需要頻繁觸發的函式,在規定時間內,只讓最後一次生效,前面的不生效。
比如點選一個按鈕,每點選一次就會觸發一次事件,在沒有加防抖函式的情況下,快速點選會導致多次觸發
// 未加防抖函式
document.getElementById('btn').onclick = function(){
console.log('我被點選了');
}
在加了防抖函式後,只會在規定時間後觸發一次
// 加了防抖函式
document.getElementById('btn').onclick = debounce(function(){
console.log('我被點選了');
},300)
具體程式碼實現
/**
* @description 函式防抖
* @param {Function} fn 需要執行函式防抖的函式
* @param {Number} interval 指定間隔時間
*/
function debounce(fn, interval = 300) {
let timeout = null // 通過閉包儲存一個標記
return function () {
clearInterval() // 把前一個定時器去掉
// 又建立一個新的定時器
timeout = setTimeout(() => {
fn.apply(this, arguments) // 指定的時間間隔之後執行fn
}, interval)
}
}
程式碼解釋
其原理就第一次呼叫函式,建立一個定時器,在指定的時間間隔之後執行程式碼。當第二次呼叫該函式時,它會清除前一次的定時器並設定另一個。如果前一個定時器已經執行過了,這個操作就沒有任何意義。然而,如果前一個定時器尚未執行,其實就是將其替換為一個新的定時器,然後延遲一定時間再執行。
應用場景
文字輸入的驗證(連續輸入文字後傳送 AJAX 請求進行驗證,驗證一次就好)