JavaScript - 防抖

2019-08-12  本文已影响0人  明里人

防抖的原理:在n秒后执行触发的事件,如果在n秒内又触发了这个事件,就以新触发事件的事件为准,n秒后再执行该事件。

第一版:
function debounce(func, wait) {
 var timeout;
 return function() {
   clearTimeout(timeout);
   timeout = setTimeout(func, wait);
 } 
}
this:

在debounce函数中,this指向window对象,我们需要将this指向func逻辑函数。

// 第二版
function debounce(func, wait) {
  var timeout;

  return function() {
    var context = this;
    clearTimeout(timeout);
    timeout = setTimeout(function () {
      func.apply(context);
    }, wait);
  }
}
event对象:

当使用debounce函数时,在func逻辑函数中打印event事件时,打印值为undefined,所以再修改一下代码:

// 第三版
function debounce(func, wait) {
  var timeout;

  return function() {
    var context = this;
    var args = arguments;

    clearTimeout(timeout);
    timeout = setTimeout(function() {
      func.apply(context,args);
    }, wait)
  }
}
立刻执行:

有这样一个需求,希望立即执行函数,然后等到n秒后再重新出发执行。
那我们加一个 immediate 参数判断是否立即执行。

// 第四版
function debounce(func, wait, immediate) {
  var timeout;
  
  return function() {
    var context = this;
    var args = arguments;
  
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      var callNow = !timeout;
      timeout = setTimeout(function () {
        timeout = null;
      }, wait);
      if (callNow) func.apply(context,args);
    } else {
      timeout = setTimeout(function () {
        func.apply(context, args);
      }, wait)
    }
  }
}
返回值:

逻辑函数func可能是有返回值的,所以我们要返回函数执行结果。但immediate为false时,执行的是setTimeout,将func.apply(context,args)赋值给变量,并将变量返回会一直是undefined,所以只在immediate为true时返回函数的执行结果。

// 第五版
function debounce(func, wait, immediate) {
  var timeout, result;
  
  return function() {
    var context = this;
    var args = arguments;
    
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      var callNow = !timeout;
      timeout = setTimeout(function () {
        timeout = null;
      }, wait);
      if (callNow) result = func.apply(context, args);
    }
    else {
      timeout = setTimeout(function() {
        func.apply(context,args);
      }, wait);
    }
    return result;
  }
}
取消:

我希望通过一个按钮,点击后,取消防抖,再去触发,就可以立即执行。

// 第六版
function debounce(func, wait, immediate) {
  var timeout, result;
  var debounced = function() {
    var context = this;
    var args = arguments;
    
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      var callNow = !timeout;
      timeout = setTimeout(function() {
        timeout = null;
      }, wait);
      if (callNow) result = func.apply(context,args);
    }
    else {
      timeout = setTimeout(function () {
        func.apply(context,args);
      }, wait);
    }
    return result;
  }
  
  debounced.cancel = function() {
    clearTimeout(timeout);
    timeout = null;
  }

  return debounced;
}

如何使用这个cancel函数?

// 例子:
var count = 1;
var container = document.getElementById('container');

function getUserAction(e) {
    container.innerHTML = count++;
};

var setUseAction = debounce(getUserAction, 10000, true);

container.onmousemove = setUseAction;

document.getElementById("button").addEventListener('click', function(){
    setUseAction.cancel();
})
上一篇 下一篇

猜你喜欢

热点阅读