面试高频题:你知道怎么实现防抖吗

459 阅读3分钟

什么是防抖

防抖(Debounce)是一种编程技巧,主要用于处理连续触发的事件,确保在一定时间内只执行一次该事件的处理函数。它的核心目的是为了限制某些函数的执行频率,以提高性能和效率,避免因短时间内频繁调用而造成的资源浪费,比如网络请求过多、DOM操作频繁等。

具体实现上,防抖函数通常会创建一个计时器,在事件被触发时,若计时器已经存在(即前一次触发还在延迟执行中),则会清除当前计时器并重新开始计时;如果在设定的延迟时间结束后没有新的事件触发,则执行目标函数。这样一来,如果事件触发非常频繁(如快速连续按键、窗口大小调整等),则只有在最后一次触发后的一段时间没有新的触发,对应的处理函数才会被执行。

例如,在搜索框的应用场景中,如果没有使用防抖,用户每输入一个字符就可能发送一次查询请求到服务器,这不仅消耗网络资源,也会给服务器带来不必要的负担。而应用了防抖技术后,只有当用户停止输入一段时间后,才会发送查询请求,大大减少了请求次数,提高了效率。

image.png

不防抖实现

  • 首先创建一个文件夹,初始化

image.png

  • 引入json-server接口,用来驱动后端

image.png

  • 创建一个json文件, 在里面放入json内容
  {
  "users": [
    {
      "id": 1,
      "name": "奶茶"
    },
    {
      "id": 2,
      "name": "wow奶茶"
    },
    {
      "id": 3,
      "name": "wow红茶"
    }
  ]
  }
  • 在package.json文件夹下,改成如下图

image.png

  • 在命令行输入 npm run dev 就可以驱动json文件,获取本地的运行地址

image.png

image.png

进入网页就可以看到自己创建的json内容

image.png

  • 直接输入/1就可以获取id为1的内容

image.png

  • 新建html文件来实现搜索框的效果
<div>
        没有防抖的input
        <input 
            type="text"
            id="unDebounce" 
            placeholder="请输入你要搜索的用户名"
        >
    </div>
    <script>
        // 不加防抖的
const inputa = document.getElementById('unDebounce');
                function handleNameSearch(e){
     
            const value = e.target.value;
            fetch('http://localhost:3000/users')
                .then(res => res.json())
                .then(data =>{

                    const users = data;
                    
                    const filterUsers= users.filter(user =>{
                        
                        return user.name.includes(value)
                        
                    })
                    console.log(filterUsers)
                })
        }

  • e.target.value每打按一次键盘就会执行一次代码,明显会造成数据的大量冗余,这对于大型搜索引擎来说,就是个巨大的灾难。 image.png

问题

  • 用户在unDebounce输入框中每输入一个字符,都会立即触发handleNameSearch函数。
  • 函数内部会获取当前输入框的值,并打印出来。实际应用中,这里会发起一个异步请求到服务器,查找匹配的用户名。
  • 由于没有防抖机制,如果用户快速连续输入,每次输入都会触发请求,可能会导致大量不必要的网络请求,增加服务器负担。

防抖实现

直接使用上面的代码

<div>
        没有防抖的input
        <input 
            type="text"
            id="unDebounce" 
            placeholder="请输入你要搜索的用户名"
        >
    </div>
    <script>
        // 不加防抖的
const inputb = document.getElementById('debounce')
                function handleNameSearch(e){
     
            const value = e.target.value;
            fetch('http://localhost:3000/users')
                .then(res => res.json())
                .then(data =>{

                    const users = data;
                    
                    const filterUsers= users.filter(user =>{
                        
                        return user.name.includes(value)
                        
                    })
                    console.log(filterUsers)
                })
        }
        const debounceNameSearch = debounce(handleNameSearch,1000)
        function debounce(func,delay){
            // 返回值必须得是函数 keyup 事件处理函数
            // let id;
            return function(args){
                clearTimeout(func.id)
                // 函数是对象,id 挂在func上 func 是闭包中的自由变量
                func.id = setTimeout(()=>{
                    func(args)
                },delay)
            }
        }

在最后添加了一个闭包,会在你输入后的1秒后,开始筛选内容,实现浏览器中的搜索推荐效果

image.png

结语

对于防抖的代码来说,推荐各位都去亲自对比和实现,时间的差异在自己实现后才能感觉到,实践是检验真理的唯一标准。