Skip to content

防抖和节流

防抖

原理

  1. 如果在200ms(预期时间内)内没有触发事件,那么就执行函数
  2. 如果在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
        }
    }
}