time: 2017-02-26 22:09:48
author: Chuck ([email protected])

函数节流和函数防抖是平时组做也页面性能优化的两种重要技巧。他们在各类需要频繁触发的工作场景中,
比如对页面onscroll和onresize事件的监听,解决由于这种频繁触发的高消耗操作会带来
性能问题。

平时在应用中,使用较多的也广为人知的是函数节流(throtting),相对来说函数防抖(debouncing)
使用得较少,两个的区别也很模糊,这篇主要从具体实现上区分throttle和debounce。

函数节流(throttling)

首先来看函数节流。函数节流的作用是,不论触发频率,单位时间内指定函数只被调用一次。就像涓涓细流一样
平缓。
具体代码实现如下:

/**
* - 节流函数
* @param {Function} fn - 要执行的函数
* @param {Number} interval - 延迟执行的时间
*/
function throttle(fn, interval) {
  var timer = null
  var firstTime = true
  return function () {
    var self = this    
    var args = arguments
    if (firstTime) { // 第一次则立即执行
      fn.apply(this, args)
      return firstTime = false
    }
    if (timer) { // 上次延迟操作还未被执行
      return false
    }
    timer = setTimeout(function () { // 延迟执行
      clearTimeout(timer)
      timer = null
      fn.apply(self, args)
    }, interval || 500)
  }
}

可以使用ES6语法来简化Throtting函数:

function throttle(fn, interval = 500) {
  var timer
  var firstTime
  return function (...args) {
    if (firstTime) {
      fn.apply(this, args)
      return firstTime = false
    }
    if (!timer) {
      timer = setTimeout(() => timer = null, interval) // 固定时间清除定时器id
      return fn.apply(this, args) // 不在定时器回调里调用故不用指定this(此处也可以按照上面思路在回调中调用,箭头函数自动绑定this)
    }
  }
}

函数防抖(Debouncing)

相对于函数节流,函数防抖是等待事件触发之后等一段时间在执行,如果触发频率高于设定的延迟时间,则一直等下下去
看到一个形象的比喻就是乘坐电梯的时候,如果电梯关闭时间是10s,这10s时间内有人进出电梯那么
电梯就会再等10s知道10s之内无人出入才会关门
防抖函数实现如下:

/**
* - 防抖函数
* @param {Function} fn - 要执行的函数
* @param {Number} interval - 延迟执行的时间
*/
function debounce(fn, interval) {
  var timer
  var firstTime = true  
  return function () {
    clearTimeout(timer) // 每次触发都先清除定时器是之处于等待状态
    var self = this
    var args = arguments
    if (firstTime) {
      firstTime = false
      return fn.apply(this, args)
    }
    timer = setTimeout(function () {
      fn.apply(self, args)
    }, interval || 500)
  }
}

同样,使用ES6语法可以简化代码:

function debounce(fn, interval = 500) {
  var timer
  var firstTime = true
  return function (...args) {
    clearTimeout(timer)
    if (firstTime) {
      firstTime = false
      return fn.apply(this, args)
    }
    timer = setTimeout(() => fn.apply(this, args), interval)
  }
}

函数节流和函数防抖功能相似,却有着不同的使用场景。根据需求合理使用会获得很大得性能提升,在平时项目中应该根据应用场景
多多使用。