yliu

时来天地皆同力,运去英雄不自由

函数防抖


前言

  1. 为什么需要使用防抖函数 当一个事件触发太多的时候会出现性能问题,比如mousemoveresizescroll等,看一个没有任何防抖的mousemove事件

1

  1. 什么是防抖? 简单就是你任意触发我只执行最后一次操作

根据上面的定义可以很轻松编写出一个简单的防抖函数

实现

// 第一版
function antiShake(call, time) {
  var i = null;
  return function() {
    clearTimeout(i);
    i = setTimeout(call, time);
  };
}

2

this 以及参数

不过这样有一个问题,就是 this 指向不正确以及参数丢失,这里以mousemove为例,触发函数的时候会有一个MouseEvent对象,如果打印函数参数会发现为undefined,下面就来修复一下

//  第二版
function antiShake(call, time) {
  var i = null;
  return function() {
    var that = this;
    var rest = arguments;
    clearTimeout(i);
    i = setTimeout(function() {
      call.apply(that, rest);
    }, time);
  };
}

立即执行

有时候我不想让他等待时间结束在执行,而是一开始就触发 4

// 第三版
function antiShake(call, time, immediately) {
  var i = null;
  return function() {
    var that = this;
    var rest = arguments;
    clearTimeout(i);
    if (immediately) {
      var reversal = !i;
      i = setTimeout(function() {
        i = null;
      }, time);

      if (reversal) {
        call.apply(that, rest);
      }
    } else {
      i = setTimeout(function() {
        call.apply(that, rest);
      }, time);
    }
  };
}

返回值

异步执行的函数我们没办法同步返回他的值,但是对于立即执行的函数,我们应当把值返回

// 第四版
function antiShake(call, time, immediately) {
  var i = null;
  return function() {
    var that = this;
    var rest = arguments;
    clearTimeout(i);
    if (immediately) {
      var reversal = !i;
      i = setTimeout(function() {
        i = null;
      }, time);

      if (reversal) {
        return call.apply(that, rest);
      }
    } else {
      i = setTimeout(function() {
        call.apply(that, rest);
      }, time);
    }
  };
}

取消

到这里基本上防抖函数就基本写完了,上述我们用mousemove事件举例,但是我想当鼠标移开的时候我想取消这个事件,这也是正常的需求,下面就来实现取消功能

function antiShake(call, time, immediately) {
  var i = null;
  function _private() {
    var that = this;
    var rest = arguments;
    clearTimeout(i);
    if (immediately) {
      var reversal = !i;
      i = setTimeout(function() {
        i = null;
      }, time);

      if (reversal) {
        return call.apply(that, rest);
      }
    } else {
      i = setTimeout(function() {
        call.apply(that, rest);
      }, time);
    }
  }
  _private.cancel = function() {
    clearTimeout(i);
    i = null;
  };
  return _private;
}

5