JavaScript 函数防抖和函数节流.

2019-04-02  本文已影响0人  人话博客

JavaScript 函数防抖和函数节流.

在浏览器执行环境中,等待主队列任务(DOM TREE & CSS Tree & render Tree) 等任务执行完毕之后.

就开始执行 EventLoop 环境事件了.

所以,某种程度上,浏览器是基于事件驱动的

既然提到了事件,那么我们最常见的就是给一些元素绑定一些事件了.

比如给一个按钮绑定一个click事件.


给元素绑定一个事件

给元素绑定一个事件,是一个非常常见的场景.

btn.onclick = function (e) {
    console.log('xxxxx')
}

这没什么大不了的.


函数节流

先不要管什么是函数节流.

上述我们给一个按钮添加了一个点击事件.

每次点击这个按钮的时候,都会触发这个事件响应函数.

这个是没毛病的.

之前也都是这么做的.

但是如果,一个哥们单身30年,手速很快

假如这个哥们一秒能点击100下. 且这又是一个发送ajax请求的按钮.

那么,每一秒钟

现在有一个需求是,这个按钮一秒钟不管点击多少下,只能执行一下.(你手速在快也没有用)

这个需求描述的就是函数节流.

某些函数可能会出现非常频繁的调用,但是在某一个周期内,不管触发多少次,实际上只能被执行一次.

所以需要这么一个机制:

<h4>节流</h4>
<p>节流就是指函数大于等于某个时间周期才能执行.否则就不执行.一个周期范围内只能处理一次.</p>
<div id="show">0</div>
<button id='jl'>函数节流</button>
  let canClick = true
  let counter = 0
  document.getElementById('jl').addEventListener('click', function () {
    if (canClick) {
      canClick = false
      console.log(++counter)
      setTimeout(() => {
        canClick = true
      }, 1000);
    }
  }, false)

利用一个 canClick 变量来标记这个按钮是否被点击.

并在一个 setTimeout 的定时器里,定时1秒去修改这个 canClick

于是,目的就达到了..每次点击之后,下一次点击有效必须要等待一秒.

但这样的做法,不具备通用性.

可以封装一个函数节流的方法,把需要节流的函数通过这个方法封装.

function throttle (handler, wait) {
    let lastTime = 0
    return function () {
        let nowTime = new Date().getTime()
        if (nowTime - lastTime > wait) {
            hanlder.apply(this,arguments)
            lastTime = nowTime
        }
    }
}
 function hanlder (e) {
    e.stopPropagation()
    show.innerText = parseInt(show.innerText) + 1
}

jl.addEventListener('click', throttle(hanlder, 1000), false)

函数节流:


函数防抖

其实和函数节流一样.

函数防抖也是用于解决某些函数频繁触发的情况.

但不同的是:

一个比较常见的场景.

在文本框内输入搜索字符,并实时的发送搜索关键字到后台.

正常情况下,一般都是这么写的.

<input type="text" name="" id="inp">
 inp.addEventListener('input', function () {
    console.log(this.value)
  }, false)
image.png

发现每次输入一个文本都会触发一次input事件响应函数.

此函数的触发频率完全取决于用户在输入框中,输入的文本快慢.

这没有什么问题,input 事件就是这么定义的.

但是对于实际场景而言,可能就出现了如下的不足:

所以,这里就需要就一个机制..

这个就是所谓的函数节流.

除非函数不触发了,且超过某个时间阈值,否则之前的事件都不会触发.

代码改写为:

 let inp = document.getElementById('inp')
  let timer = null
  inp.addEventListener('input', function () {
    clearTimeout(timer)
    timer = setTimeout(() => {
      console.log(this.value)  
    }, 1000);
    
  }, false)

结果:

image.png

只有等待用户操作停止了,并达到某一个等待的时间阈值,再最后触发事件响应函数.

上述的代码不具备通用性.

封装函数节流方法 debounce

function debounce (hanlder, wait) {
    let timer = null
    return function () {
        clearTimeout(timer)
        timer = setTimeout(() => {
            hanlder.apply(this,arguments)
        }, wait)
    }
}

所以整体代码可以改写为

 function inputHanlder(e) {
    console.log(this.value, e)
  }
  // 函数防抖 , 频繁
  function debounce(hanlder, wait) {
    let timer = null
    return function () {
      clearTimeout(timer)
      timer = setTimeout(() => {
        hanlder.apply(this, arguments)
      }, wait);
    }
  }

  inp.addEventListener('input',debounce(inputHanlder,1000), false)

总结

一个只执行一次(函数节流).

一个不满足条件就一次也不执行(函数防抖).

上一篇下一篇

猜你喜欢

热点阅读