Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2017.2.21 - 深入浅出throttle和debounce #12

Open
stephenLYZ opened this issue Feb 21, 2017 · 0 comments
Open

2017.2.21 - 深入浅出throttle和debounce #12

stephenLYZ opened this issue Feb 21, 2017 · 0 comments

Comments

@stephenLYZ
Copy link
Owner

前言

之前我在写一个获取github用户信息的小应用的时候,遇到了一个问题: 由于我在input上绑定了keyup的监听事件(也就是ajax请求),每按下一次键盘键就会发出一次ajax请求,显然频繁的网络的请求会造成很大的性能问题。这里的解决办法就是用函数去抖(debounce)。那么什么是函数去抖?他的基友函数节流(throttle)又是什么?他们有什么区别?他们应用的场景有分别是什么?下面一一来解答。

函数去抖

简单来说,函数去抖背后的思想指的是 某函数只有在过完一段时间后并且该段时间内不被调用才会被执行。一旦在指定的时间间隔内调用该函数,该函数就不会被执行。那上面例子来说,在没有去抖之前:

function ajax(content) {
  console.log('ajax request ' + content)
}

var input = document.getElementById('search')
input.addEventListener('keyup', function(e) {
  ajax(e.target.value)
})

qq20170221-151811 2x

可以看到,每按下一次键盘键就会发送一次ajax请求。现在用debounce()方法来改进:

jsbin

function debounce(func, delay) {
  return function(args) {
    var _this = this
    var _args = args
    clearTimeout(func.id)
    func.id = setTimeout(function() {
      func.call(_this, _args)
    }, delay)
 }
}

function ajax(value) {
  console.log('ajax request ' + value)
}

var debounceAjax = debounce(ajax, 1000)

var input = document.getElementById('search')
input.addEventListener('keyup', function(e) {
  debounceAjax(e.target.value)
})

throttle1

可以看到当你输入的时候,并不会发送ajax请求,当停止输入并且在指定间隔内没有输入时候,才会执行相应的回调函数。下面我们来讲讲他的好基友,函数节流(throttle)。

函数节流

函数节流指的是 某函数在指定的一个时间段周期性的间断执行。 什么意思呢,举上面的例子,当在input中不断键入数值的时候,debounce是在你停止输入一段时间后执行回调函数,而throttle则是在你输入过程中每隔一段固定的时间就执行回调函数。
代码

function throttle(func, delay) {
  var last, deferTimer
  return function() {
    var _this = this
    var _args = arguments
    var now = +new Date()
    if(last && now < last + delay) {
      clearTimeout(deferTimer)
      deferTimer = setTimeout(function() {
        last = now
        func.apply(_this, _args)
      }, delay)
    }else {
      last = now
      func.apply(_this, _args)
    }
  }
}

function ajax(value) {
  console.log('ajax request ' + value)
}

var throttleAjax = throttle(ajax, 1000)

var input = document.getElementById('search')
input.addEventListener('keyup', function(e) {
  throttleAjax(e.target.value)
})

throttle2
可以看出,当我在input中不断键入值时,ajax回调函数每过1s执行一次。

异同

从上面的内容可以知道,函数去抖和函数分流都是解决某一事件频繁触发的问题,比如input的ajax请求、scroll事件等等。即使如此,他们的实现原理却大相庭径,简单来说,函数去抖在一段时间只执行一次,而函数节流则是间隔时间段执行。比如,一个举个例子,小明吃饼干,有两种吃法,第一种是每过一段时间间隔吃一块饼干,这是函数节流,第二种是第一块饼干吃完后得过一段时间才能吃第二块饼干,期间不能吃饼干,这是函数去抖。

应用场景

  • 发送一个ajax表单,给一个button绑定click事件,并且监听触发ajax请求。如果是debounce,则用户不管点多少次,都只会发送一次请求;如果是throttle,不断点击的过程中会间隔发送请求。这时候最好使用debounce.
  • 监听滚动事件判断是否到页面底部自动加载更多,如果是debounce,则只有在用户停止滚动的时候的才会判断是否到了底部,如果是throttle,则页面滚动的过程中会间隔判断是否到达底部。 此时最好使用throttle

其他

  • DOM 元素的拖拽功能实现(mousemove)
  • 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
  • 计算鼠标移动的距离(mousemove)
  • Canvas 模拟画板功能(mousemove)
  • 搜索联想(keyup)

参考: lessfish/underscore-analysis#20

@stephenLYZ stephenLYZ changed the title 深入浅出throttle和debounce 2017.2.21 - 深入浅出throttle和debounce Mar 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant