函数截流和防抖

2020/01/10 功能实现

如何从程序上避免用户的频繁操作?

通过函数防抖或者函数截流来实现,使用防抖还是截流,随你的需求而定

函数执行频率对比

函数防抖

当一个动作连续触发,或者频繁操作,而我们不需那么快的实时响应,只关注最后的结果。

比如:

  1. 手机号、邮箱验证输入检测 => 可以在输入完成之后进行检验是否符合,没必要每一次输入都要检测,我们更加关心的是最后是否是符合规则

  2. 搜索框关键字搜索输入,不必要每输入一个字就发送一次请求,这样对服务器也不好,频繁请求。=> 可以在用户最后一次输入完,再发送请求

  3. 窗口大小 Resize 大小变化的时候,网页大小自适应或者触发某一个事件 => 只需窗口调整完成后,计算窗口大小。防止重复渲染

我上面说的两个例子都是,在一段时间内频繁的操作,而我们将多次执行的事件合并成一次事件执行。这就是防抖

<div class="wrapper" onclick='x()'>点击</div>

// immediate 表示第一次点击是不是要执行,默认不执行
function debounce(fn,wait=300,immediate=false){
  let timeout = ''
  return function (){
  const argus = arguments
  let context = this;
//因为 clearTimeout(timeout)只会清除定时器的执行,并不会清除定时器返回的id
  if(timeout) clearTimeout(timeout)
  // 立即执行
  if(immediate){
    // 如果是已经执行过了,就不执行
    let callNow = !timeout
    // 执行过一次以后 timeout要赋值操作
    timeout = setTimeout(function(){
        timeout = null;// 如果没有清空timeout 会导致timeout一直有值,后面就不会在执行
    }, wait)
    if(callNow) fn.apply(context,argus)
  }else{
    timeout = setTimeout(()=>{
      fn.apply(context,argus)
    },wait)
   }
  }
}
function handleClick(){
  console.log('一直被点击');
}
let x=debounce(handleClick,500,true)

只要 setTimeout() 被调用就会返回一个唯一的 idclearTimeout 这个唯一的 id 这个定时器也就被清除,当这个定时器 id 被删除的时候,这个定时器也就被清了。一旦定时器被清了,就是开始新的计时,也就实现了多次执行事件合并成一次事件执行

JavaScript 专题之跟着 underscore 学防抖

函数截流

当一个动作连续触发,或者频繁操作,而我们不希望看到密密麻麻,或者是快速跳动的东西(好比是定时器,一段时间内只执行一次操作)

比如:

滚动加载数据,滚动加载更多,滚动到底部,我们快速的滚动,但是我们希望看到数据是缓慢的加载,能够看到数据加载的一个过程,而不是飞快的数据出现在我们的面前

高频点击一个按钮出现消息提示,我们希望看到的是有间隔出现消息提示,而不是全部重叠再一起提醒

我上面说的两个例子都是,在一段时间内频繁的操作,但是函数事件执行频率被稀释了,间隔一段时间执行一次。

<body>
  <div id='div'>函数截流</div>
  <script>
    const div = document.getElementById('div')
    // 第一次执行的时候需要等到wait秒
    const throttle = (func, wait) => {
      let timer = null
      return () => {
        if (timer) return
        timer = setTimeout(() => {
          func()
          timer = null // timer为空了,就会再一次执行到这里来
        }, wait)
      }
    }

    function show() {
      console.log('函数截流')
    }
    const funthrottle = throttle(show, 1000)

    div.addEventListener('click', () => {
      funthrottle()
    })
  </script>
</body>

使用时间戳的形式实现截流

funvtion throttle(fn wait){
 previous = 0
 return function (){
   let context = this
   let arugs = arguments
   const now = +now Date()
   if(now-previous > wait){
     fn.apply(context,argus)
     previous = now
   }
 }
}

JavaScript 专题之跟着 underscore 学节流

加锁

有这么一个场景:用户提交表单,用户注册,用户发布等等,如果服务端返回比较慢,用户一直停留在当前页面,避免不了的就有用户着急呀,就一直按提交数据按钮导致一直请求服务器,出现了大量重复的数据。

解决方案:加锁+节流 => x 秒内不允许提交

因为节流在第一次点击的时候需要等待 x 秒之后才会才会像服务器发起请求,显然这不是我们想要的,我们要的是,第一次点击的时候就像服务器发起请求,后面再次点击是用防抖还是截流看我们实际的生活场景了

function throttle(func,delay=600){
  let lock = false
  return (...args)=>{
    if(lock) return
    func(...args)
    lock = true
    setTimeout(()=>lock=false,delay)
  }
}

参考文章

浅析函数防抖与函数节流


有时候,虽然素未谋面。却已相识很久,很微妙也很知足。在逝去的岁月里,我们在某一刻,共同经历着一样的情愫。

如果喜欢我的话,我们可以互相关注,相互学习的哟!互相鼓励,你的关注是我最大的动力来源

sunseekers

Search

    Table of Contents