节流:(事件n秒内被触发多次,则执行一次)
在规定的时间内无论触发多少次事件,在计时结束后都只触发一次(第一次或者最后一次 )的操作(滚动scroll, resize, 鼠标的mouseover mouseup, mousedown 事件等等)
有两种方式:常用的定时器还有时间戳判断; 规定时间是2000毫秒,scroll事件
1.定时器方式:
当触发事件的时候 先判断当前定时器是否为空, 如果非空 说明上一次的滚动事件定时器回调函数还未执行,就不需要再一次触发定时器; 如果为空,说明上一次的滚动事件中的定时器回调函数在2s内已经执行,并且清空了定时器,所以需要重新触发定时器,执行这一次的事件
this.timer = null
scrollHome(event) {
// setTimeout 方式 节流 就是在规定的时间内 无论触发多少次事件,都只执行一次 ,执行完成之后
// 清空定时器,设置为Null ,
if(!this.timer) { // 全局设置timer
this.timer = setTimeout(() => {
console.log(event)
clearTimeout(this.timer)
this.timer = null
}, 2000)
}
}
2. 时间戳的方式:
先定义一个全局的时间戳,用来记录上次执行函数的时间为0,当执行滚动事件时,首先先去执行后面的操作,然后记录lastTime和nowTime, 需要判断当前日期时间戳和那个全局的时间戳的间隔是否大于等于2000毫秒, 如果是则触发回调函数,设置上次触发回调函数的时间为now
// 第一次执行
this.lastTime = 0
scrollHome(event) {
// 时间戳的方式
let nowTime = new Date().getTime() //当前时间戳
if(nowTime - this.lastTime >= 2000) {
this.lastTime = nowTime
console.log(event) // 调用的函数
}
}
// 节流 利用闭包保留变量值 无论间隔期间有没有多次操作 每隔一段时间只触发一次
export function throttle(fn, delay = 300) {
let last = 0 // 上次触发时间
return (...args) => {
const now = Date.now()
if (now - last > delay) { // 先执行 第一次就会执行
last = now
fn.apply(this, args)
}
}
}
防抖:(在事件触发n秒后被执行,如果在n秒之内又触发,则重新计时)
设置定时器, 如果在定时器启动之前,又触发了事件,那么定时器需要清空,重新计时;
inputDebounce() {
// 设置定时器, 如果在定时器启动之前,又触发了事件,那么定时器需要清空,重新计时
// 每当事件被触发 则清除定时器
if(this.debounceTime) {
clearTimeout(this.debounceTime)
}
this.debounceTime = setTimeout(() => {
console.log('输入文字')
}, 2000)
},
闭包形式
function debounce(fn, delay) {
let timer = null
return function(...arg){
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
fn.apply(this, arg)
}, delay)
}
}
但是有一个问题就是如果用户在启动定时器之前又触发了操作,重新计时,频繁这样操作,那么定时器任务就会一直延迟 ,也会造成问题, 导致定时器任务一直不执行;那么如何解决:
需要设置一个底线时间,就是我们的延迟时间,如果在定时器未启动之前频繁操作,在延迟时间之前的操作都可以重新设置定时器
// debounce 利用闭包保留变量值 防止短时间内多次点击 在间隔时间内如果再次触发,则重新计算时间(查询或者提交)需要和节流结合 防止极端情况: 一直点击 事件一直不触发
export function debounce(fn, delay = 300) {
let last = 0
return (...args) => {
const now = Date.now()
if (now - last < delay) { // 需要有一个时间底线
if (this.debounceTimer) {
clearTimeout(this.debounceTimer)
}
this.debounceTimer = setTimeout(() => {
fn.apply(this, args)
clearTimeout(this.debounceTimer)
}, delay)
} else { // 到达了时间底线 自动执行回调函数
last = now
fn.apply(this, args)
clearTimeout(this.debounceTimer)
}
}
}