主题
防抖和节流
防抖
原理
- 如果在
200ms
(预期时间内)内没有触发事件,那么就执行函数 - 如果在
200ms
(预期时间内)内再次触发事件,那么当前的计时取消,重新开始计时
应用场景
- 实时搜索
- 拖拽
实现
js
// 参数一:哪个函数要进行防抖
// 参数二:延迟多少秒
function debounce(fn, delay) {
// 形成闭包,以防止 timer 成为全局污染
let timer = null
return function() {
const that = this, // 这里获取 this 是因为 setTimeout 里的 this 发生改变
e = arguments // 这里获取事件 e
if(timer) {
// 如果 timer 还在,证明在执行时间内又触发事件
clearTimeout(timer)
// 则重新定时
timer = setTimeout(function() {
// 让函数执行,并把 e 传给函数
fn.apply(that, e)
}, delay)
}else {
// 说明已经执行过了,开始下一轮定时
timer = setTimeout(function() {
// 让函数执行,并把 e 传给函数
fn.apply(that, e)
}, delay)
}
}
}
// 可简化
function debounce(fn, delay) {
let timer = null
return function(...arg) {
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arg)
}, delay)
}
}
// 先立即执行一次,再对后面函数防抖
function debounce(fn, delay) {
let timer = null
return function(...arg) {
if (timer) clearTimeout(timer)
if (!timer) fn.apply(this, arg) // 如果定时器不存在,则说明延时已过,可以立即执行函数
timer = setTimeout(() => {
timer = null
}, delay)
}
}
// 故可设置一个标志位,判断是否先立即执行一次
function debounce(fn, delay, immediate = false){
let timer = null
return function(...arg){
if(timer) clearTimeout(timer)
if(immediate) {
if (!timer) fn.apply(this, arg)
timer = setTimeout(() => {
timer = null
}, delay)
} else {
timer = setTimeout(() => {
fn.apply(this, arg)
}, delay)
}
}
}
节流
实现场景
- 下拉加载
- 抢购疯狂点击
实现
js
// 参数一:要进行节流的函数
// 参数二:多长时间里只允许执行函数一次
function throttle(fn, wait){
// 形成闭包,以防止 lasttime 成为全局污染
let lasttime = 0
return function(...arg){
let nowtime = Date.now()
// 如果新的时间 - 旧时间 比 允许时间 长才能执行函数
if(nowtime - lasttime > wait){
// 函数自己执行,并且把 事件e 传给他
fn.apply(this, arg)
lasttime = nowtime
}
}
}