详解简单debounce的实现

138 阅读2分钟

1. 什么是防抖

简单理解,防抖就是当用户频繁触发某一个事件的时候,我们不总是立马发送请求,而是延长一段时间发送请求,举个栗子:

现在我们需要实现一个搜索推荐功能,当用户在输入框输入文字的时候,我们不对每次用户输入立马发送请求,而是等待用户输入停止后过一段时间才向服务器发送请求

假设现在我们有一个需求,实现搜索推荐,在用户停止输入3秒后才发送请求给服务器(这意味着如果用户停止输入3秒以内之后继续输入,则我们不做请求发送)

2. 实现简单的防抖

为了实现这个需求,我们需要实现防抖,延后我们的函数的执行,我们知道setTimeout函数可以做到这一点,例如我们可以使用setTimeout(function, 3000)在3秒后执行function. 但注意,如果我们直接这么使用,并不能实现防抖。

注意到需求: 如果用户停止输入3秒以内之后继续输入,则我们不做请求发送, 所以我们需要在用户继续输入的时候重置我们的timer,重新计时。既然我们需要重置timer,那么必然需要先定义timer,并且在每次触发函数的时候可以重置timer,我们自然地想到了使用一个包装函数,然后将真正要执行的函数写成一个闭包

0. 模拟用户暂停然后继续输入 image.png

1. 示例代码

const debounce = (mainFunction, delay) => {
  // store the timer id
  let timer;
  
  // that is a closure
  return function (...args) {
    // call this first time, it simply does nothing here
    clearTimeout(timer);
    timer = setTimeout(() => {
      mainFunction(...args);
    }, delay)
  }
}

function searchData() {
  console.log("searchData executed");
}

const debouncedSearchData = debounce(searchData, 3000);
debouncedSearchData();

1. 防抖函数程序调用时,JS内存图

为什么上述的写法,可以形成一个闭包,做到调用防抖函数的时候可以做到clearTimeout(timer)从而实现我们的需求,接下来的内存图解析基于ES3:

image.png

当debounce执行上下文和debouncedSearchData上下文执行完被弹出的时候:

从GC的角度,AO1仍然是可达的,因此不会被回收,从而保留了debouncedSearchData的外部环境,实现了闭包,从而可以使得我们实现在用户停止输入2秒内又继续输入(我们可以清除timer)

image.png