理解并实现防抖(debounce)和节流(throttle)

324 阅读2分钟

应用场景

两个函数都是为了优化高频率事件,如用户input事件、window.resize、window.scroll,具体哪些场景用哪个,要理解两个函数,然后根据需求来看

防抖(debounce)

防抖(debounce)在处理多频率事件时,可以理解成:

在限定时间内再次触发,会重新计时

比如我们时间设置为5秒后执行事件,在这5秒内有很多次事件发生,每次的事件都会清掉之前的计时,只从最后一次事件触发往后计时5秒

// 编写思路:需要接收一个函数参数,返回包装后的函数,业务函数(参数函数)的执行频次被控制了
function debounce(fn, delay) {
  var timer;  // 每次事件执行会共用一个计时器变量
  return function (...args) { // 接收一个函数,返回一个包装函数,事件触发时实际执行的是此函数
    clearTimeout(timer); // 在delay时间内再次触发事件,会清掉之前的计时器,重新计时
    timer = setTimeout(() => {
      fn.apply(this, args) // 传递this, 传递执行函数的参数
    }, delay); //delay后执行
  }
};
// 业务主体函数
function reqSearch(v){
  console.log('ready to request:', v)
}
// debounce包装后的函数
var dReqSearch = debounce(reqSearch, 1000);
var input = document.querySelector('input');
input.addEventListener('input', function(e){
  dReqSearch(e.target.value)
})

节流(throttle)

节流(throttle)节省不必要的流量;在处理多频率事件时,可以理解成: 在限定一段时间内触发的多次事件,我们只处理一次,其他的视为无效事件

也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活(类似于技能冷却时间)

function throttle(fn, delay) {
  var valid = true; //是否处理事件的开关
  return function(...args){
    if(valid) { // 有效事件进来后,settimeout开始计时,不处理后续事件,直到限定时间过去后
      valid = false;
      fn.apply(this, args) // 传递this, 传递执行函数的参数
      setTimeout(() => {
        valid = true
      }, delay);
    }
  }
}

lodash的防抖和节流

lodash的函数里多了两个配置项leading和trailing,可以决定在延迟开始前和后执行函数

debounce API

_.debounce(func, [wait=0], [options={}])

func (Function): 要防抖动的函数。

[wait=0] (number): 需要延迟的毫秒数。

[options={}] (Object): 选项对象。

[options.leading=false] (boolean): 指定在延迟开始前调用,默认false。

[options.maxWait] (number): 设置 func 允许被延迟的最大值。

[options.trailing=true] (boolean): 指定在延迟结束后调用,默认true

throttle API

_.throttle(func, [wait=0], [options={}])

func (Function): 要节流的函数。

[wait=0] (number): 需要节流的毫秒数。

[options={}] (Object): 选项对象。

[options.leading=true] (boolean): 指定调用在节流开始前,默认true。

[options.trailing=true] (boolean): 指定调用在节流结束后,默认true

参考文章

segmentfault.com/a/119000001… www.cnblogs.com/dreamsqin/p…