面试官:请手写一个防抖节流🤔,我:在我的博客里写了,想要啊?你去复制就好了😎

发布于:2024-04-29 ⋅ 阅读:(15) ⋅ 点赞:(0)

防抖节流,前端面试中,考察频率非常高;当然在实际的开发中,许多业务场景经常也会应用到。

如果你还不知道防抖节流是啥的话,或者最近在准备面试但是忘记了,本文将带你再次学习如何手写防抖节流,让你在面试中实现一个简单的防抖节流。😘

防抖

基本概念

只有当事件停止触发一段时间后才会执行事件中的函数,确保短时间内多次触发仅在最后一次执行

场景

输入框搜索联想,频繁输入时只在用户停止输入一段时间后发送请求

GIF 2024-3-6 14-39-41.gif

防抖丐版实现

分析

前面触发的点击事件我们没有去执行,但是到最后一次触发事件后的等待期结束后执行

image.png

代码

<body>
    <button id="btn">提交</button>
    <script>
        const btn = document.querySelector('button')
        function sendMsg(msg) {
            const currentDate = new Date();
            console.log('sendMsg函数的this指向是',this,'\n',
            '点击事件传递进来的参数是',msg,'\n',currentDate.toLocaleString())
        }
        
        btn.addEventListener('click', debounce(sendMsg, 1000))//防抖函数
        // btn.addEventListener('click', sendMsg)//没有防抖的话
        function debounce(fn, delay) {
            let timer
            return function(){
                let args = arguments
                if(timer) clearTimeout(timer)
                
                timer = setTimeout(()=>{
                    fn.call(this,...args )
                },delay)
                
            }
        }
    </script>
</body>

代码讲解

我们使用debounce函数来包裹要执行的函数,传入设置的时间间隔; debounce函数中使用到了闭包来保证多次调用的话timer变量的一致性, 执行一次debounce函数就会对计时器timer变量判断,如果有计时器就重新设定,如果在设定的间隔中触发,那么定时器就会不断刷新,实现最后一次等待之后再触发,来实现防抖效果

这里的call方法和arguments对象

如果需要执行的函数fn如果当中有通过this指向dom对象的代码的话,因为fn函数被节流函数debounce包裹,所以需要使用call来设定正确fnthis指向

又因为函数fn可能也需要依赖点击事件传入的参数,所以通过使用arguments对象来获取到传入debounce函数返回的匿名函数的参数,来确保代码正确运行

效果

没有防抖,触发一次点击事件就立马执行,要执行的函数逻辑

未开启防抖.gif

开启防抖,只在最后一次事件触发之后再执行函数

开启防抖.gif

节流

基本概念

节流就是在过了特定时间间隔被触发事件中的函数执行一次,周期性地执行被触发事件中的函数,而不限制最后一个事件

应用场景

滚动事件监听,实时更新但不密集执行,如滚动加载

节流.gif

还有一个非常常见的场景,就是在打游戏的时候想多打出点伤害,手速通常会很快,但是 游戏中按键连击,只会确保每段时间只触发一次伤害计算

节流2.gif

节流丐版实现

分析

节流概括来说就是,按照固定的时间间隔执行,无视触发频率

代码

<body>
    <button>按钮</button>
    <script>
        let btn = document.querySelector('button')
        function sendMsg(e) {
            const currentDate = new Date()
            console.log('sendMsg的this指向是',this,'\n','点击事件传递进来的参数时',e,'\n',currentDate.toLocaleString())
        }
         btn.addEventListener('click',throttle(sendMsg,1000))//节流函数
         //没有节流
        //btn.addEventListener('click',sendMsg)
        function throttle(fn,wait) {
            let preTime = Date.now()
            return function () {
                let nowTime = Date.now()
                if (nowTime - preTime >= wait) {
                    fn.apply(this,arguments)
                    preTime = nowTime
                }
            }
        }
    </script>
</body>

代码讲解

了解到防抖之后,节流也就非常好理解了

Date.now() 将会得到一个表示自 1970 年 1 月 1 日 00:00:00 UTC 以来所经过的毫秒数的整数值。 这个方法是 Date 对象的一个静态成员函数,意味着你无需创建 Date 对象实例就能调用它

通过闭包设定一个初始时间保证多次调用函数都是这个变量,如果函数的执行时间-初始时间大于或等于设定的时间间隔,则执行函数,并刷新初始时间,否则啥也不干;就可以实现等待设定的时间之后才能触发的节流效果。

这里的arguments对象没有解构是因为apply方法接受数组为参数。

实现效果

使用节流函数,多次点击因为小于设定好的时间间隔所以并不会执行,只有当等待时间等于或者大于设定好的间隔才会执行

开启节流.gif

还在学习中,水平有限,本文可能存在纰漏或错误,如有问题欢迎指正,感谢你阅读这篇文章,如果你觉得写得还行的话,不要忘记点赞、评论、收藏哦!祝生活愉快!😘

本人目前在准备春招,也希望和一起准备春招的佬们互相交流一下,一起冲刺大厂,欢迎私信评论或加v:guanyiiu1314