防抖、節流函數通常應用在一些高頻觸發的方法,例如搜索框聯想輸入的input事件、onmousemove事件、click事件等等;實際上業務不須要屢次觸發,那麼就須要用到防抖或者節流來處理啦。javascript
簡單的能夠這樣理解java
防抖函數:瘋狂點擊按鈕,每次點擊的時間間隔都小於規定時間,那麼相應的方法不會執行閉包
節流函數:瘋狂點擊按鈕,規定的時間間隔內只觸發一次相應的方法app
是否當即執行的區別就是,當即執行執行的是第一次觸發的狀態,非當即執行觸發的是最後一次的狀態dom
let Debounce = function (fn, delay = 300, immediate = false) {
let timer = null // 閉包存儲setTimeout狀態
return function () {
let self = this // 事件源this
let args = arguments // 接收事件源的event
if (timer) clearTimeout(timer) // 存在就清除執行fn的定時器
if (immediate) { // 當即執行
let callNow = !timer // 執行fn的狀態
timer = setTimeout(function () {
timer = null
}, delay)
if (callNow) fn.apply(self, args)
} else { // 非當即執行
timer = setTimeout(function () { // 或者使用箭頭函數將this指向dom
fn.apply(self, args)
}, delay)
}
}
}
let con1 = document.querySelector('.con1')
let con2 = document.querySelector('.con2')
let con3 = document.querySelector('.con3')
let addNum = function (args) {
console.log(this, args)
this.innerText = (+this.innerText) + 1
}
con1.onmousemove = addNum // 無防抖
con2.onmousemove = Debounce(addNum) // 防抖
con3.onmousemove = Debounce(addNum, 300, true) // 防抖(當即執行)
複製代碼
// 基礎版節流
let Throttle = function (fn, delay = 500) {
let flag = true
return function () {
let self = this
let args = [...arguments]
if (!flag) return
flag = false
setTimeout(function () {
fn.apply(self, args)
flag = true
}, delay)
}
}
let con1 = document.querySelector('.con1')
let con2 = document.querySelector('.con2')
let addNum = function (args) {
console.log(this, args)
this.innerText = (+this.innerText) + 1
}
con1.onmousemove = addNum // 無節流
con2.onmousemove = Throttle(addNum, 1000) // 節流
複製代碼
節流函數的另外一種寫法,防抖函數也能夠使用時間戳做爲判斷條件函數
// 時間間隔做爲判斷
let ThrottleTime = function (fn, delay = 500) {
let preTime = 0 // 記錄上一次執行時間
return function () {
let self = this, // 保留執行時候的的this
args = [...arguments], // 執行時候的傳入參數
nowTime = +new Date() // 記錄當前的時間
if (nowTime - preTime >= delay) {
preTime = nowTime // 更新執行時間
fn.apply(self, args)
}
}
}
複製代碼
加上當即執行狀態ui
// 是否當即執行
let ThrottlePro = function (fn, delay = 500, immediate = false) {
let preTime = 0 // 記錄上一次執行時間
return function () {
let self = this, // 保留執行時候的的this
args = [...arguments], // 執行時候的傳入參數
nowTime = +new Date(), // 記錄當前的時間
flag = nowTime - preTime >= delay // 執行命令
if (immediate) { // 是否當即執行
if (!flag) return
preTime = nowTime // 更新執行時間
fn.apply(self, args)
} else {
if (!flag) return // 不知足執行條件
preTime = nowTime
setTimeout(function () {
fn.apply(self, args)
}, delay)
}
}
}
複製代碼