JS中防抖函数的实现原理


theme: Chinese-red

前言

在网页制作中我们经常会碰到这样一个场景—比如:需要在操作停止后一段时间,才向服务端发送请求,而不是每一次操作都向服务器发送请求,这样会发送过多的无效请求给服务器造成了巨大的压力。这个时候我们就需要使用到JS中一个重要的技术防抖 , 接下来我将给大家详细介绍什么是防抖以及防抖的使用场景

image.png

什么是防抖

用官方的语言来解释防抖:

防抖技术是一种编程技巧,用于限制某个函数在一定时间内只能执行一次。它特别适用于处理那些可能会因为连续触发而产生大量重复执行的事件,例如窗口调整大小、输入框内容变化、按钮点击等。防抖的核心思想是:当事件被触发时,并不立即执行函数,而是等待一个特定的延迟时间,如果在这个延迟时间内事件又被触发了,则重新开始计时,直到延迟时间结束后才真正执行函数。

个人对于防抖的理解是:

以游戏举例,当我们按下回程时,需要经过几秒的时间才能实现回程。

防抖的应用场景

应用场景:

  • 搜索框的实时搜索建议:防止用户输入过程中频繁发送请求。
  • 窗口大小调整时的重绘操作:避免因窗口频繁调整而持续触发重排重绘,影响性能。
  • 按钮防连击:确保按钮不会因为用户快速连续点击而多次触发同一动作。

防抖的作用

防抖的主要作用是在处理频繁触发的事件时,限制事件处理函数的执行频率,确保只有在事件停止触发一段时间后才执行相应的操作。具体来说,防抖可以用于:

  • 减少事件处理函数的执行次数:当用户在短时间内频繁触发某个事件时(比如输入框输入文字、窗口大小变化等),防抖可以确保事件处理函数只在最后一次事件触发后执行,从而减少不必要的函数执行次数,提高性能。

  • 控制异步请求的发送频率:在需要发送异步请求的场景下,防抖可以确保只有在用户停止操作一段时间后才发送请求,避免频繁的请求发送。

  • 提高用户体验:通过限制事件处理函数的执行频率,可以减少页面上的不必要的刷新或操作,提高用户体验。
    总的来说,防抖能够有效地控制函数的执行时机,避免过度频繁的执行,从而更好地处理用户操作或优化页面性能。

防抖的实现

没使用防抖函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>没加防抖函数</title>
</head>

<body>
    <button id="btn">按钮</button>

    <script>
        let btn = document.getElementById('btn');
        btn.addEventListener('click', function () {
            console.log("按钮被点击了")
        })
    </script>
</body>

</html>

image.png

使用了防抖函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn">提交</button>

    <script>
        let btn = document.getElementById('btn')

        function handle(e) {
            // 模拟ajax请求
            console.log('提交事件触发了', e);
        }

        btn.addEventListener('click', debounce(handle))

        // 防抖函数
        function debounce(fn) {
            let timer = null
            console.log(this)

            return function (e) {
                const that = this
                // console.log(that)
                clearTimeout(timer)
                timer = setTimeout(function () {
                    fn.call(that, e)
                }, 1000)

            }

        }
    </script>
</body>

</html>

image.png

可以看到当使用了防抖时,无论我们点击多少下按钮,都只会在最后一次点击结束后并且经过一定的时间才会触发函数。可以大大的减少对服务器的访问量,减轻服务器的压力。

实现原理

闭包

以上代码为例,这段代码中使用了闭包来创建了一个防抖函数 debounce,闭包使得内部函数能够访问到外部函数中的变量 timer 和 fn,而这两个变量又不会被外部函数以外的代码所访问到。这样就保证了 timer 的状态能够在多次调用 debounce 的过程中被共享和更新。

闭包的用途:

内部函数一定可以访问外部函数的变量,当内部函数被拿到外部函数之外调用时,即使外部函数执行完毕,但是内部函数对外部函数中的变量依然存在引用,那么这些被引用的变量会以一个集合的方式保存下来。

this的指向问题

debounce 函数内部,使用了 setTimeout 来实现延时执行函数 fn。这里的关键是在 setTimeout 内部,使用了 fn.call(that, e) 来确保函数 fn 在执行时能够正确地绑定 this。因为在 JavaScript 中,this 的指向取决于函数的调用方式,而在事件监听器中,this 通常指向触发事件的元素。所以,为了保证 handle 函数内部的 this 指向正确,需要通过 call 或者 apply 方法手动指定 this,这里通过 fn.call(that, e) 来确保 handle 函数内部的 this 指向与外部相同。

另外,在 btn.addEventListener('click', debounce(handle)) 中,虽然 debounce(handle) 是作为参数传递给 addEventListener 的,但实际上传递给 addEventListener 的是一个新的函数,该函数是 debounce(handle) 返回的闭包函数。这是因为 debounce 返回了一个函数,而不是直接返回 handle 函数本身。

本篇文章就到此为止啦,希望通过这篇文章能对你理解JS防抖有所帮助,本人水平有限难免会有纰漏,欢迎大家指正。如觉得这篇文章对你有帮助的话,欢迎点赞收藏加关注,感谢支持🌹🌹。

image.png
本人掘金地址欢迎大家访问!

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小A远离BUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值