前言

  1. 节流防抖 是什么
  2. 应用场景区分
  3. 实现

参考

https://zhuanlan.zhihu.com/p/38313717

https://juejin.im/post/5b8de829f265da43623c4261

节流和防抖

处理频繁请求的业务场景,比如「输入框keyup实时搜索查询请求」 「页面滚动触发的事件」,不处理的话 可能会频繁请求给服务器带去太大压力吧,滚动或者浏览器缩放这样的会带来前端性能问题。

所以我们可以控制在一定时间内的请求次数,节流防抖都是干这个事情,应用场景有点差别

实现

设置/清除最小时间段的定时器setTimeout/clearTimeout

场景1:实时搜索,input-keyup每次输入后触发keyup事件去发请求 我们可以设置一个定时间延迟一段时间(delay:1000)比如1s后去执行这个请求,如果用户在1s内又输入触发了该事件则清除该定时器,重新设置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 模拟请求
function ajax(content) {
	console.log('ajax request---', new Date().toLocaleTimeString(), content)  
}

function debounce(func, delay) {
  let timer
  return function(args) {
    clearTimeout(timer)
    setTimeout(() => {
      func.call(this, args)
    }, delay)
  }
}

const debounceAjax = debounce(ajax, 1000)   // 防抖函数

input.addEventListener('keyup', function(e) {
  debounceAjax(e.target.value)
})

场景2:相对于上述keydown/keyup来说 resize/drag事件触发的频率会更加高(不间断),所以如果还用上述防抖函数来写的话,可能很难触绑定事件。比如上述delay=1s,要是每隔0.5s去触发一次事件的话,那么要执行的请求则永远在setTimeout不会执行,所以这个时候。我们需要做的是,在上述基础上加上一个「至少执行一次的时间间隔」,这个就需要比较两次请求的时间差来判断是否要执行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
function throttle(func, delay) { 
  let last, deferTimer
  return function(args) {
    console.log('23232')
    let now = +new Date()    
    if(last && now < last + delay) {
      clearTimeout(deferTimer)
      deferTimer = setTimeout(() => {
        last = now
        func.call(this, args)
      }, delay);
    }else {
      last = now
      func.call(this, args)
    }
  }
}
const throttleAjax = throttle(ajax, 1000)
input.addEventListener('keyup', function(e) {
  debounceAjax(e.target.value)
})

小结

总之,防抖和节流都是为了减少一段时间内的频繁请求/操作次数,减少服务端处理请求压力或者客户端渲染压力。节流相比于防抖而言,处理更加频繁的事件操作比如鼠标滚动 浏览器缩放等等连续过程的事件,防抖的话比较适合实时输入搜索请求吧。