防抖与节流

1.防抖

高频事件触发后,n秒内(定时器计时)执行一次,如果在函数执行前再次触发,则重新计时。

思路:再次触发的时候,取消上次的定时器。

function debounce(fn) {
  let timer = null;
  return function () {
    clearTimeout(timer);
    timer = setTimeout(() => {
      // this 指向 input,
      fn.apply(this, arguments);
      // 不修改 this 指向的话,doRequest 中, this 指向 window
     // fn()
    }, 500);
  };
}

function doRequest() {
  console.log(this.value);
  console.log(arguments);
}

document.getElementById("app").innerHTML = "防抖输入框 <input id='input' />";

document.getElementById("input").addEventListener("input", debounce(doRequest));

不改变 this 指向,效果如下:

2.节流

定义一个函数,n 秒内最多执行一次,如果在函数执行前再次触发,则跳过。

思路:n 秒内执行的时候,判断是否有定时器,如果有,则跳过此次执行。

function throttle(fn) {
  let timer = null;
  return function () {
    if (timer) return;
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      clearTimeout(timer);
      timer = null;
    }, 3000);
  };
}

function doRequest() {
  console.log(`${parseInt(new Date().getTime() / 1000, 10)}:` + this.value);
}

document.getElementById("app").innerHTML = "节流输入框 <input id='input' />";

document.getElementById("input").addEventListener("input", throttle(doRequest));

换种写法:

function throttle(fn) {
  let lock = false;
  return function () {
    if (lock) return;
    lock = true;
    fn.apply(this, arguments);

    setTimeout(() => {
      lock = false;
    }, 3000);
  };
}

运行结果:

扩展

问:throttle 或 debounce 中 return 的函数能用箭头函数吗?

答:不能,如果使用箭头函数,return 函数中this指向 window ;不使用箭头函数,this 指向 input。