天天看点

underscore 源码阅读【三】一、节流二、防抖

一、节流

什么是节流?

就像春节回家过安检一样,你会发现有个保安人员拦住你,等到安检机前没人的时候再让你进。

一个函数频繁地被调用可能导致异常情况,所以要让它隔段时间再执行。

为什么要节流?

这样做可以避免因人流太大导致安检机一次要处理的行李过多,人员拥挤等状况。

js中的节流可以避免资源浪费,异常情况的发生等。

_.throttle

var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);
           

创建并返回一个像节流阀一样的函数,当重复调用函数的时候,至少每隔 wait毫秒调用一次该函数。对于想控制一些触发频率较高的事件有帮助。

_.throttle = function(func, wait, options) {
    var timeout, context, args, result
    var previous = 0
    if (!options) options = {}

    var later = function() {
      previous = options.leading === false ? 0 : _.now()
      timeout = null
      result = func.apply(context, args)
      if (!timeout) context = args = null
    }

    var throttled = function() {
      var now = _.now()
      if (!previous && options.leading === false) previous = now
      var remaining = wait - (now - previous)
      context = this
      args = arguments
      if (remaining <= 0 || remaining > wait) {
        if (timeout) {
          clearTimeout(timeout)
          timeout = null
        }
        previous = now
        result = func.apply(context, args)
        if (!timeout) context = args = null
      } else if (!timeout && options.trailing !== false) {
        timeout = setTimeout(later, remaining)
      }
      return result
    }

    throttled.cancel = function() {
      clearTimeout(timeout)
      previous = 0
      timeout = context = args = null
    }

    return throttled
  }
           
函数 作用
now 获取当前的时间戳
clearTimeout 取消延时器

讲解

throttle内部定义了三个方法

  • later:下一次的执行
  • throttled:定义本次执行立即执行还是等待执行
  • cancel:取消延时的执行队列

核心的实现逻辑表述为:

每次执行时根据上一次的执行时间快照判断这次的执行是否wait间隔内,如果是则延时剩余时间调用,否则,立即执行 并将等待的延时器清空。

underscore 源码阅读【三】一、节流二、防抖

二、防抖

什么是防抖?

实时搜索中,输入框每输入一个字符就查询一次,因为输入结果的不确定性就很容易造成“性能爆炸”,且会给用户造成困扰。

在事件被触发n秒后,再去执行回调函数。如果n秒内该事件被重新触发,则重新计时。结果就是将频繁触发的事件合并为一次,且在最后执行。

为什么要防抖?

js中的防抖可以避免“性能爆炸”,异常情况的发生等。

_.debounce

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
           

返回 function 函数的防反跳版本, 将延迟函数的执行(真正的执行)在函数最后一次调用时刻的 wait 毫秒之后. 对于必须在一些输入(多是一些用户操作)停止到达之后执行的行为有帮助。 例如: 渲染一个Markdown格式的评论预览, 当窗口停止改变大小之后重新计算布局, 等等.

_.debounce = function(func, wait, immediate) {
    var timeout, result

    var later = function(context, args) {
      timeout = null
      if (args) result = func.apply(context, args)
    }

    var debounced = restArguments(function(args) {
      if (timeout) clearTimeout(timeout)
      if (immediate) {
        var callNow = !timeout
        timeout = setTimeout(later, wait)
        if (callNow) result = func.apply(this, args)
      } else {
        timeout = _.delay(later, wait, this, args)
      }

      return result
    })

    debounced.cancel = function() {
      clearTimeout(timeout)
      timeout = null
    }

    return debounced
  }
           
函数 作用
delay 延时执行器

讲解

debounced内部定义了三个方法

  • later:下一次的执行
  • debounced:主函数
  • cancel:取消延时的执行队列
underscore 源码阅读【三】一、节流二、防抖

继续阅读