【JS】 由浅入深防抖和节流

846 阅读7分钟

序言

在实际的 Web 开发中,经常会遇到用户频繁触发某个事件的情况,比如按钮被快速连续点击、输入框被快速输入等。这种频繁触发事件可能会导致一些问题,比如性能损耗重复请求发送页面状态混乱等。为了解决这些问题,我们需要一种机制来控制事件处理函数的执行频率,这就需要清楚我们今天要讲的防抖函数的概念。

防抖函数概述

什么是防抖函数

防抖函数是一种用于控制事件处理函数执行频率的技术。它的核心思想是,当一个事件被触发后,在指定的时间间隔内如果事件再次被触发,则将重置计时器,直到事件停止触发并且经过了指定的时间间隔后才执行相应的处理函数

防抖函数的作用

防抖函数主要用于解决因事件频繁触发而引发的性能问题和不必要的重复操作。通过防抖,我们可以确保在短时间内多次触发同一事件时,只有最后一次触发会导致实际的处理函数执行,从而有效地减少不必要的操作提升性能

如何实现防抖功能

实现防抖功能的关键在于利用定时器闭包来控制事件处理函数的执行时机。在事件被触发时,通过清除之前设置的定时器并重新设置新的定时器,从而实现对事件处理函数的延迟执行,进而达到防抖的效果。

通过以上介绍,我们初步了解了防抖函数的基本概念、作用以及实现原理。接下来,我们将结合具体的代码示例,深入探讨如何在 JavaScript 中实现一个简单但功能强大的防抖函数。

代码解析

如果今天我们想要完成一个功能,就是当用户点击一个提交按钮的时候,我们会在一秒中后给予执行,但是如果一秒内用户再次点击了这个按钮,我们将重新计时,并在新得一秒后给予执行。所以我们可以把今天的任务分解成以下步骤:

  • 1. 获取按钮元素 首先,我们需要获取需要添加防抖功能的按钮元素,可以通过 document.getElementById() 或者其他 DOM 方法获取到对应的按钮元素。

  • 2. 定义事件处理函数 我们需要定义一个事件处理函数,该函数将会成为防抖函数的参数。这个函数将会在防抖函数内部被调用。

  • 3. 添加事件监听器 通过 addEventListener() 方法给按钮元素添加相应的事件监听器,比如 click 事件。

  • 4. 编写防抖函数 下面是一个简单的防抖函数示例:

function debounce(fn,delay){
            let timer;
            return function(){
                let args = arguments
                if(timer) clearTimeout(timer)
                timer = setTimeout(() => {
                    fn.call(this, ...args)
                },delay)
            }
        }

在上述防抖函数示例中,我们用到了闭包以及箭头函数THIS绑定规则ES6新增的解构运算知识,对其不了解的可以看看我之前的文章【前端面试】深入理解 JS 中 调用栈 作用域链 闭包 我们利用return函数形成一个闭包里面存放timer用于每次我们覆盖之前timer的值来重新计时。当我们用()=>{}箭头函数时里面的THIS就会默认指向return function()中的this,如果我们不将其绑定,则会指向全局,浏览器端则是window,不了解的朋友可以看看我之前的这篇文章深入探讨 JavaScript 中 this 的绑定规则及箭头函数。 在实际场景中,我们的函数可能不只有一个参数,我们在实现防抖的过程,不能把其原来的功能干没了,所以我们还需要传入它原本就拥有的另外一部分参数,这里我们使用了...arguments来将其原本所有参数“掏出来”(解构)再放入fn函数中调用。

防抖函数实现原理详细分析

  • 1. 防抖函数的返回值 防抖函数内部返回了一个匿名函数,该匿名函数利用闭包的特性,可以访问到外部函数的变量和参数。这个返回的函数将成为实际的事件处理函数,并且会被绑定到按钮的事件监听器上。

  • 2. 定时器的运用 在防抖函数内部,我们通过设置一个定时器 timer 来控制事件处理函数的执行时机。每当事件被触发时,都会先清除之前设置的定时器,然后再次设置新的定时器,从而延迟执行事件处理函数。

  • 3. 函数参数和上下文的传递 在返回的匿名函数内部,我们使用了箭头函数和call方法来确保事件处理函数能够在正确的上下文(this 指向)下执行,并且能够正确地接收事件对象和其他参数。

  • 4. 延迟执行 通过 setTimeout 方法,我们实现了对事件处理函数的延迟执行,从而确保只有在事件停止触发并且经过了指定的延迟时间后才会执行真正的处理逻辑,并且对传入的参数进行解构防止影响原函数的其他作用。

以上是对防抖函数实现原理的详细解析,我们通过深入理解防抖函数的工作原理,可以更好地应用它来解决实际的开发问题,提升用户体验和系统性能。

利用防抖函数开启实战

以下是一个利用防抖函数的示例,当我们点击提交按钮时,一秒钟后会输出提交完成,但是如果我们疯狂点击提交按钮,则会一直不执行,直到最后一次点击并且过了1s后才会打印出提交成功,以下是完整代码示例:

let btn = document.getElementById('btn')
        function send(e){
            console.log(this,"提交完成",e);
        }

        btn.addEventListener('click',debounce(send,1000))
        
        function debounce(fn,delay){
            let timer;

            return function(){
                let args = arguments

                if(timer) clearTimeout(timer)
                timer = setTimeout(() => {
                    fn.call(this, ...args)
                },delay)
            }

        }

防抖函数应用场景

防抖函数广泛应用于需要控制事件频繁触发的场景,特别是对于一些性能敏感或者需要减少不必要请求的交互操作中。以下是一些常见的应用场景:

  • 1. 输入框搜索建议 当用户在输入框中输入关键字时,可以利用防抖函数来延迟发送搜索请求,以避免在用户快速输入时频繁触发搜索请求造成不必要的服务器压力。

  • 2. 窗口大小调整 在窗口大小调整时,可以使用防抖函数来延迟执行一些需要重新计算布局或者重绘界面的操作,以减少不必要的重复计算。

  • 3. 按钮提交事件 当用户频繁点击提交按钮时,可以通过防抖函数来确保只有最后一次点击会触发实际的提交操作,避免用户误操作导致多次提交。

通过合理应用防抖函数,可以有效地优化用户体验,减少不必要的资源消耗,提升系统性能。

总结

防抖函数是指在规定的时间内没有执行第二次的操作,才执行逻辑。我们可以通过闭包,箭头函数以及ES6的解构新特性等功能手写一个防抖函数。

到这里我们今天的文章就结束了,喜欢的小伙伴的可以点赞+关注,作者后续会持续更新类似干货文章。

感谢大家的阅读,点点赞吧♥

如果想了解更多有用的干货,关注➕收藏 面试不迷茫

博主的开源Git仓库: gitee.com/cheng-bingw…

更多内容:【AIGC】更牛逼的”情感分析“大模型 这次我们用OpenAI”自动完成模型“省去复杂的代码一步到位