likes
comments
collection
share

不是哥们?你怎么抖成这样了?求你进来学学防抖吧!全方位深入剖析防抖的奥秘

作者站长头像
站长
· 阅读数 24

前言

古有猴哥三打白骨精,白骨精 ======> 噶

今有用户疯狂点请求,服务器 ======> 噶

所以这防抖咱必须得学会!!!

本文就来讲解一下Web前端中防抖的奥秘吧!!!!

为什么要做防抖

在一些功能中,需要向服务器发送请求来获取数据。如果用户在短时间内疯狂的去点击触发这个功能,就会导致大量的请求被发送到服务器,造成资源浪费,同时也会使页面频繁刷新数据,降低用户的体验。

在这种情况下,使用防抖就显得非常重要了

防抖可以限制函数的执行频率,只在事件触发的间隔期之后执行一次

具有以下的效果:

  1. 提高页面性能: 减少不必要的函数调用,降低页面负载。
  2. 优化用户体验: 避免页面频繁刷新,让交互更加流畅。
  3. 减轻服务器压力: 减少无谓的网络请求,降低服务器的负担。

防抖代码详解

未防抖

首先我们分析以下的代码的执行结果是什么?

var btn = document.getElementById('btn');

btn.addEventListener('click', function(){
        console.log("提交")
    )
}

首先通过document.getElementById('btn') 方法获取了页面中 id 为 btn 的元素

使用 addEventListener 方法为该元素添加了一个点击事件监听。

当用户点击这个元素时,会执行console.log("提交") 输出字符串 "提交"

不是哥们?你怎么抖成这样了?求你进来学学防抖吧!全方位深入剖析防抖的奥秘

我们可以看到,由于按钮并没有做防抖处理,当我们疯狂点击提交按钮时,就会使得函数被疯狂的调用

这显然是不行的,哒咩哒咩!!!!!!

防抖

接下来我们开始去实现防抖效果了

首先分析一下防抖是一个怎么样的效果呢?

简单来说就是在规定的时间内没有下一次的触发,就执行函数

那么我们要怎么样去实现这个效果呢????

于是我们就想到了定时器触发执行函数,当我们在规定时间内没有触发,定时器就正常的去执行了函数,如果触发了,我们就把原先的定时器删了,创建一个新的定时器,这样我们不就实现了防抖,说干就干!

var btn = document.getElementById('btn');

function handle() {
    console.log('提交');
}
        
btn.addEventListener('click', debounce(handle))

//防抖函数
function debounce(fn) {
    let timer = null;
    //这是一个闭包
    return function () {
        //如果第二次的时间没到一秒就销毁上一次的计时器
        clearTimeout(timer)
        timer = setTimeout(fn, 1000)
    }
}

这段代码通过使用闭包和 setTimeout 的方式,实现了一个简单而实用的防抖功能。当用户在 1 秒内连续触发事件时,只有在 1 秒的间隔后才会执行一次 handle 函数,从而避免了不必要的重复操作。

不是哥们?你怎么抖成这样了?求你进来学学防抖吧!全方位深入剖析防抖的奥秘

可以看到这段代码已经帮我们实现了防抖的效果了,但是这段代码是有不足之处的,我们继续讲解

如果我们执行一下代码,结果是如何?

var btn = document.getElementById('btn');

function handle() {
    console.log(this);
}
btn.addEventListener('click', handle)

可以看到结果为btn

不是哥们?你怎么抖成这样了?求你进来学学防抖吧!全方位深入剖析防抖的奥秘

由于addEventListener决定handle的执行,所以addEventListener干扰了this,让this不指向全局

这里我们可以想到一个防抖函数肯定是不能说去改变了原有的this指向的

可是我们这里却改变了this的指向

var btn = document.getElementById('btn');

function handle() {
    console.log('提交', this);
}

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

function debounce(fn) {
    let timer = null;
    return function () {
        clearTimeout(timer)
        timer = setTimeout(() => {  
            fn()
        }, 1000)
    }
}

可以看到this的指向变为了win

不是哥们?你怎么抖成这样了?求你进来学学防抖吧!全方位深入剖析防抖的奥秘

我们需要将指向修正回来

这里我们可以看到addEventListener决定执行的函数不再是handle而是我们的防抖函数debounce,所以很显然,debounce返回的函数里面的this才是我们想要的this,我们只需要将handle里的this指向debounce返回的函数里的this即可完成修正

var btn = document.getElementById('btn');

function handle(e) {
    console.log(this);
}

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

function debounce(fn) {
    let timer = null;
    return function () {
        clearTimeout(timer)
        timer = setTimeout(() => {
            // this就是一个对象
            fn.call(this)
        }, 1000)
    }
}

此时handle的this就是正确的了

不是哥们?你怎么抖成这样了?求你进来学学防抖吧!全方位深入剖析防抖的奥秘

但是这里还有一个问题,addEventListener的回调函数会接收一个事件对象 e。这个事件对象包含了事件的相关信息,比如触发事件的元素、鼠标/键盘事件的坐标等

但是由于现在使用了防抖函数的原因,就使得e丢失了,在handle里面没有了e,而这个事件对象也在function里面,我们需要把他也传给handle

接下来修改代码

var btn = document.getElementById('btn');

function handle(e) {
    console.log(e);
    console.log(this);
}

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

function debounce(fn) {
    let timer = null;
    return function (e) {
        clearTimeout(timer)
        timer = setTimeout(() => {
            fn.call(this, e)
        }, 1000)
    }
}

这样我们就实现了完整的防抖函数

不是哥们?你怎么抖成这样了?求你进来学学防抖吧!全方位深入剖析防抖的奥秘

总结

本文全方位深入剖析防抖的奥秘,通过结合代码以及其实现效果,由浅入深得讲解防抖的全部实现流程

希望能够帮助到你,如果对你有所帮助,别忘了一键三连,点赞、收藏加评论呦~

转载自:https://juejin.cn/post/7388444606457085971
评论
请登录