我们一般在监听input事件、scroll事件或者resize事件时,会有每次更改都触发的操作。每次操作都触发本质上说肯定是没问题的,但在于是否需要每次更改都去执行函数体?
就拿scroll事件来说,如果我们在频繁执行scroll的时候减少触发次数会不会有影响?
input事件每次更改都去服务器请求搜索的返回结果,所以每次触发都会请求一次,我们如果让input事件后延迟去执行,甚至等待用户的所有input事件后只执行一次搜索会不会更好?
这也就有了很多的优化方法:
函数节流
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。 节流会稀释函数的执行频率。
// 时间戳法
function $throttle(fn, wait) {
// 记录上次执行的时间,否则为0
let prevTime = 0
return function () {
let nowDate = Date.now()
// 判断此时的时间是否已经超过了上次的执行时间
if (nowDate - prevTime > wait) {
// 执行函数体
fn.apply(this, arguments)
// 赋值下次时间
prevTime = nowDate
}
}
}
// 定时器法
function $throttle(fn, wait) {
// 初始定时器
let timer = null
return function (...arg) {
// 如果上次定时器已经被执行过,才进入
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arg)
// 执行后函数体后再把定时器清空
timer = null
}, wait)
}
}
}
// 应用:
let num = 0
window.addEventListener('scroll', $throttle(function () {
console.log(num++)
}, 200))
函数防抖
指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
function $debounce (fn, wait) {
let timer = null
return (...arg) => {
// 如果存在定时器则清空
if (timer) clearTimeout(timer)
// 重新设置定时器执行
timer = setTimeout(() => {
fn.apply(fn, arg)
}, wait)
}
}
// 应用:
let num = 0
window.addEventListener('scroll', $debounce(function () {
console.log(num++)
}, 200))