防抖和节流-‘帕金森’网友的良方

前言

各位掘友们平时都没少上网噜,在冲浪的时候没少遇到过网络卡顿的情况,每当点击链接或者图片没有反应的时候,就会烦躁地一通乱点,那么掘友们有没有想过在你的一番操作之下,这个程序究竟在背地里运行了多少次?一次?好多次?好好好,今天我们就要来聊聊点点点的那些事。

防抖

掘友们从名字就能看出点门道来。防抖------就是防止 '帕金森' 网友的手抖。防抖是指在一定时间内,如果事件被频繁触发,只执行最后一次事件。可以用于优化一些高频率触发的事件,比如窗口大小改变,滚动事件等。也就是说当网友点击一个提交按钮后1s后进行提交,但是网友在1s内重复点击,那么就从最后一次点击开始计算1s后进行提交。

那么我们要如何实现这个效果呢?我们一起来看看:

html 复制代码
<!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> 
        function send(e){
            console.log(this,'提交完成',e);
        }
        let btn = document.getElementById('btn')
        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)
            } 
        }
    </script>
</body>
</html>

首先我们设置了一个button用来模拟点击提交事件。接下来,为了监听按钮我们得在按钮上设置一个监听器。点击按钮以后,我们就运行debounce()

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

debounce()中传入了两个参数,fndelayfn 是一个函数,也就是我们要进行的各种操作,也就是点击按钮后的一些操作,delay 就是我们设置的延迟时间。在函数体内,我们先声明了一个timer ,用来记录我们的计时器,如果在之前点击了按钮,那么timer 就不为空,当再次点击按钮时,判断timer 不为空,于是调用clearTimeout()方法,将定时器重置,实现在一定时间内只执行最后一次操作的效果。

细心的掘友会发现,如果我的send()方法中传入多个参数,那么怎么办呢?我们可以看到,在函数体内调用fn()方法的时候使用了解构,让fn()传入的实参解构再调用,那么无论fn()中有多少个形参,都能使用防抖。(不了解解构的掘友们请移步"跃迁ES6:探索JavaScript语言的最新进展(一)")

在这个防抖函数的实现中,fn 函数是通过 call() 方法调用的。具体来说,fn.call(this, ...args) 的作用是:将 fn 函数中的 this 指向当前上下文中的 this(也就是防抖函数返回的新函数的执行环境),并将传入的 args 参数展开后作为参数传递给 fn 函数。

节流

好好好,刚才我们从防抖的名字就能看出点门道来,那么这节流又是一个啥玩意?节流(throttle)指的是在一定时间间隔内只执行一次函数,用于优化高频率触发的事件,比如 scrollresizemousemove 等。与防抖不同的是,节流函数会按照固定的时间间隔执行函数,而不是在等待一段时间后才执行。

我们话不多说,先上代码:

html 复制代码
<!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>
</body>
<script>
    function send(){
        console.log('提交完成');
    }
    let btn = document.getElementById('btn')
    btn.addEventListener('click',throttle(send,1000))
    function throttle(fn,delay){
        let prevTime = Date.now()
        return function(){
           if(Date.now()-prevTime>delay){
             fn.apply(this,arguments)
             prevTime = Date.now()
           }
        }
    }
</script>
</html>

同样的我们看到throttle()方法

js 复制代码
function throttle(fn,delay){
        let prevTime = Date.now()
        return function(){
           if(Date.now()-prevTime>delay){
             fn.apply(this,arguments)
             prevTime = Date.now()
           }
        }
    }

与防抖方法不一样的地方是,不管我们在delay 这段时间内点击了多少次,我们只在 delay 时间过去后调用一次fn 方法。那么我们是如何记录时间的呢?这里使用到了Date.now(),这个方法返回的是现在距离1970年经过的毫秒数,储存在prevTime 变量中,如果后面的点击时间距离第一次点击时间大于delay 则运行 fn ,掘友们要注意的是,在运行以后,要将prevTime的时间进行更新,这样才能保证下一次点击事件的正确运行。

结尾

在实际开发中,合理地运用节流和防抖可以减少不必要的函数执行,降低资源消耗,提升页面响应速度。无论是处理 DOM 事件、AJAX 请求还是其他异步操作,都可以考虑使用节流和防抖来优化程序性能。希望本文对你有所帮助,也欢迎读者在实际项目中尝试运用这两种技巧,从而改善用户体验,提升应用性能。"

相关推荐
神夜大侠30 分钟前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱32 分钟前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号1 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy72931 小时前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html
前端郭德纲1 小时前
ES6的Iterator 和 for...of 循环
前端·ecmascript·es6
究极无敌暴龙战神X1 小时前
前端学习之ES6+
开发语言·javascript·ecmascript
王解1 小时前
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
前端·webpack·es6
欲游山河十万里1 小时前
(02)ES6教程——Map、Set、Reflect、Proxy、字符串、数值、对象、数组、函数
前端·ecmascript·es6
明辉光焱1 小时前
【ES6】ES6中,如何实现桥接模式?
前端·javascript·es6·桥接模式
PyAIGCMaster2 小时前
python环境中,敏感数据的存储与读取问题解决方案
服务器·前端·python