技巧-防抖和节流的简单理解

33 阅读2分钟

一、防抖

防抖函数,可以这么理解,不是立即做,而是等待一段时间之后再做,如果等待期间又触发,那就重新计时。举个例子,就像游戏里的回城,如果被打断了,那就重新回城,又或者像电梯关门,如果在等待期间有人进电梯了,就会重新计算时间。 应用场景挺多的,比如搜索引擎里的搜索。输入关键词完毕后,等待一小段时间,才会发送http请求,而不是一输入内容就发送请求。

  1. 声明debounce函数
export const debounce = function (callback, delay) {
  setTimeout(() => {
    callback()
  }, delay);
};

然而,这个只是将函数延迟了,并没有达到只执行一次的效果。所以可以这样做,声明一个timer,每一次调用这个debounce函数,就先把定时器清除了,这样就能保证定时器只执行一次.

var timer;
export const debounce = function (callback, delay) {
  clearTimeout(timer);
  timer = setTimeout(() => {
    callback();
  }, delay);
};

但是这样做,明显是污染了全局变量,所以可以考虑使用闭包

export const debounce = function (callback, delay) {
  var timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      callback();
    }, delay);
  };
};

此时已经是能够实现效果了,可以实现只触发一次。

//高阶函数:函数内部返回一个新的函数
const debounce = utils.debounce(function () {
  console.log("searchValue", searchValue.value);
}, 1000);

const onSearch = () => {
  debounce();
};

还有完善一下传参。

//xx.vue

//高阶函数:函数内部返回一个新的函数
const debounce = utils.debounce(function (val) {
  console.log('val',val);
}, 1000);

const onSearch = () => {
  debounce(searchValue.value);
};


//debounce.js

export const debounce = function (callback, delay) {
  var timer;
  return function () {
    clearTimeout(timer);
    var args = arguments;
    timer = setTimeout(()=> {
      callback.apply(null, args);
    }, delay);
  };
};

二、节流

节流函数,可以这么理解,在一定时间内,只执行一次,现在写一下。

  1. 等待一段时间后才触发。 就像连续触发,开始一秒后执行一次,触发停止了,过了一秒执行最后一次。
//xxx.vue
const throttle = utils.throttle(function (val) {
  console.log('val',val);
}, 1000);

const onSearch = () => {
  throttle(searchValue.value);
};

//throttle.js
var timer;
  return function () {
    if (timer) return;
    var args = arguments;
    timer = setTimeout(() => {
      callback.apply(null, args);
      timer = null;
    }, delay);
  };

  1. 立即触发。 就像连续触发,刚开始触发时执行一次,触发停止了就不再执行。
export const throttle = function (callback, delay) {
  var t;
  return function () {
    if (!t || Date.now() - t >= delay) {
      //之前没有及时 或 距离上次执行的时间大于规定时间
      callback.apply(null, arguments);
      t = Date.now(); //得到当前时间搓
    }
  };
};

3.两者结合,默认立即触发

//throttle.js

export const throttle = function (callback, delay, immediately) {
  if (immediately === undefined) {
    immediately = true;
  }

  if (immediately) {
    var t;
    return function () {
      if (!t || Date.now() - t >= delay) {
        //之前没有及时 或 距离上次执行的时间大于规定时间
        callback.apply(null, arguments);
        t = Date.now(); //得到当前时间搓
      }
    };
  } else {
    var timer;
    return function () {
      if (timer) return;
      var args = arguments;
      timer = setTimeout(() => {
        callback.apply(null, args);
        timer = null;
      }, delay);
    };
  }
};