王子与变形怪的故事之——如何实现防抖节流

前言

什么是防抖节流?相信各位从字面意思上也能理解个大概了,防抖,防的就是用户的手抖,例如用户在点击登录的时候,就有可能一不小心手抖点击了两百次登录,这个时候,我们难道要把两百次的数据都交给后端去验证吗?从气喘吁吁的服务器和后端想杀人的眼神就能看出来这显然是不需要的,这个时候防抖功能就可以只把最后一次提交放过去,而将其余的提交按住。而节流则稍微宽松一些,会在规定的时间内放行一次,例如一秒放一次,或者0.5秒放一次。了解什么是防抖节流之后,我们来试着用代码去实现。

正文

防抖

有一个王子,外出狩猎归来即将回到自己的祖国。但是国王的巫师预知到会有一群变形怪变成王子的模样混进来,但是只有最后进来的人才是真正的王子并且真正的王子到了之后的两个小时内不会有变形怪出现。这个时候,作为守卫的你该怎么办?见一个王子杀一个?显然不对。因为你不知道谁是最后一个,所以你应该是见到王子之后,将他拦下来,两个小时内如果没有第二个一模一样的王子出现,那就放行,如果有,就把前一个干掉。防抖亦是如此,接下来我就封装一个函数去实现。

为了更好模拟用户发送请求,首先我先写一个按钮在页面上,并获取到元素赋给变量btn

    <button id="btn">提交</button>
const btn = document.getElementById('btn')
btn.addEventListener('click', debounce(send), 1000)
function send() {
    console.log('请求已发送');
   }

 这里我设置的时间是1秒,也就是说只有停止点击的1s之后,请求才会发送。接下来继续编写debounce方法

function debounce(fn, delay) {
            let timer
            return function () {
                if (timer) {
                    clearTimeout(timer)
                }
                timer = setTimeout(fn, delay)
            }
        }

这里的timer就是王子,当我们点击按钮,debounce中return出来的函数就会被执行,这个时候timer只被声明了而没有赋值,所以是undefined。所以会被赋值成为一个定时器,其中的fn就是发送请求的函数,delay就是我们定义的时间。当我们第二次点击的时候,return出来的函数又被执行一次,然而这个时候上一个timer由于闭包的原因已经被保留下来了,
轻松入门JavaScript闭包:从零开始 – 掘金 (juejin.cn)
所以存在,也就是这个时候,守卫发现了第二个王子,所以会通过clearTimeout函数毫不留情将前一个timer干掉,直到有一个timer在经历的delay时长之后,才被运行出来。但这只是一个丐中丐中丐版的,因为没有考虑fn中的参数以及this指向问题,所以可以稍微修改一下

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

            }

        }

这里利用箭头函数和.call方法将this指向了匿名函数身上,而匿名函数是在addEventListener里面调用的,那么addEventListener就会将被调用函数的this强行指向监听的dom元素,如此一来this指向问题就解决了。而参数问题则是利用拿到匿名函数的类数组arguments并将其赋值给args,随后在通过解构的方式塞回给fn。这样,一个简单的防抖函数就算是完成了

节流

现在,不是一个王子,而是一群王子,而且每两个小时之内只最多有一个真王子会出现,而且只有第一个进来的才是王子。这个时候第一个王子一出现,立马放行,与此同时开始计时,两个小时内,所有出现的王子格杀勿论,直到两小时结束,再次放行第一个。想要用代码实现也不难
HTML和绑定部分还是一样的这里将监听事件的函数改为theottle

        function theottle(fn, delay) {
            let timer = -delay
            return function () {
                if (Date.now() - timer >= delay) {
                    fn.call(this, ...arguments)
                    timer = Date.now()
                }
            }
        }

之后还是定义一个timer并将他设置为-delay,因为timer是在代码加载完毕之后立即执行的,所以为了防止极限情况,我们这里设置为-delay而不是0,为的就是第一个王子哪怕是0点0分0秒进来的也能放行。然后,timer立刻记录下当前时间,当第二次触发的时候,立即查看当前的时间减去上一次点击的时间是否大于delay,大于的话就执行this,并重新记录第二次的执行时间,否则不予理会。如此一来,简单节流的就也被我们实现好了。

总结

对于项目来说,特别是在涉及到发送请求等地方加上防抖或者节流,不仅降低了后端代码的压力,同时,还能避免多次请求数据造成的错误,所以能够掌握防抖节流对于前端开发来说还是很有必要的。

原文链接:https://juejin.cn/post/7344993022076534834 作者:我真的很困

(0)
上一篇 2024年3月12日 上午10:59
下一篇 2024年3月12日 上午11:10

相关推荐

发表回复

登录后才能评论