防抖、节流函数一般应用在一些高频触发的方法,例如搜索框联想输入的input事件、onmousemove事件、click事件等等;实际上业务不需要多次触发,那么就需要用到防抖或者节流来处理啦。
简单的可以这样理解
防抖函数:疯狂点击按钮,每次点击的时间间隔都小于规定时间,那么相应的方法不会执行
节流函数:疯狂点击按钮,规定的时间间隔内只触发一次相应的方法
是否立即执行的区别就是,立即执行执行的是第一次触发的状态,非立即执行触发的是最后一次的状态
防抖
代码
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)
}
}
}
复制代码
加上立即执行状态
// 是否立即执行
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)
}
}
}
复制代码