防抖与节流

本文介绍了防抖和节流两种技术,用于优化在高频率事件如resize、scroll等下的代码执行,通过设定延迟时间和控制执行次数来减少性能消耗和资源请求。文章还提供了防抖和节流的实现示例,并讨论了如何将它们与业务逻辑优雅地封装。
摘要由CSDN通过智能技术生成

防抖与节流

防抖节流优化高频率执行代码的一种手段。

当函数绑定一些持续触发的事件如:resize、scroll、mousemove ,键盘输入,多次快速click等等,如果每次触发都要执行一次函数,会带来性能下降,资源请求太频繁等问题,为了解决这些问题,防抖(debounce) 和 节流(throttle)就出现了;

比喻:
游戏中的回城就可以认为是防抖,在回城的读秒过程中,如果再次执行回城操作,那么会重新进行读秒,只有整个读秒过程都没有再次执行回城操作,那么等到读秒结束才能成功回城。
节流类似于技能cd,不管你按了多少次,必须等到cd结束后才能释放技能。也就是说在如果在cd时间段,不管你触发了几次事件,只会执行一次。只有当下一次cd转换,才会再次执行。

防抖

定义: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时;
简单版本:

//timeout是需要进行防抖处理的函数,第二个是延迟时间
 function debounce(timeout, fn) {
 //实现防抖函数的核心是使用setTimeout
 	//time变量用于保存setTimeout返回的Id
        let _time = null
        return function () {
        	//如果time不是0,定时器存在,将定时器清除
            let _arg = arguments
            clearTimeout(_time)
            _time = setTimeout(() => {
                fn.apply(this, _arg)
            }, timeout)
        }
    }

示例:

<input type="text"/>
let int = document.querySelector("input");
let time = null;  //初始化定时器
    int.oninput = function(){
        if(time != null){  //判断是否已存在定时器
            clearTimeout(time)  //清空定时器
        }
        time = setTimeout(() => {
            console.log(this.value);   //模拟业务逻辑
        }, 500);
    }

效果
请添加图片描述

上面防抖函数的实现,已经基本上可以实现防抖的效果,但是还是会有一点小问题,比如说this的指向和原来的函数是不一致的以及参数问题。将防抖函数与业务逻辑单独封装

let int = document.querySelector("input");
int.oninput = debounce(task,500)

//业务逻辑
function task(){
    console.log(this.value);
}
//防抖函数
//封装一个名为debounce,且返回值为函数的防抖函数,来替代oninput后承接的内容。因为返回值为函数,所以用闭包思想来实现封装
function debounce(fn, delay){
    var time = null;
    //防抖函数里传入业务逻辑fn()和延迟时间delay优化全局变量time,把变量time作为私有变量放入debounce函数中
    return function(){
    //此处是防抖逻辑
        if(time != null){
            clearTimeout(time)
    }

    time = setTimeout(() => {
            fn.call(this) // 注:此处需改变this指针,否则业务逻辑中的this指向window
        }, delay);
    } 
}

节流

定义: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时;控制执行次数,n秒内多次触发事件只有1次生效

简单版本:

// interval 间隔时间,也就是cd的长短
function throttle(fn, interval) {
    //该变量用于记录上一次函数的执行事件
    let lastTime = 0
    
    const _throttle = function(...args) {
        // 获取当前时间
        const nowTime = new Date().getTime()
        
        // cd剩余时间
        const remainTime = nowTime - lastTime
        // 如果剩余时间大于间隔时间,也就是说可以再次执行函数
        if (remainTime - interval >= 0) {
            fn.apply(this, args)
            // 将上一次函数执行的时间设置为nowTime,这样下次才能重新进入cd
            lastTime = nowTime
        }
    }
    // 返回_throttle函数
    return _throttle
}

示例:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
       body{
        height: 10000px;
    }
    </style>
</head>
<body>
</body>
<script>
window.onscroll = function(){  
    console.log('触发')
}
var flag = true;
var time = null;

window.onscroll = function(){  
    if(flag){   //标记变量为true时开始计时
        time = setTimeout(() => {
            console.log('触发')
            flag = true;
        }, 500);
    }
    flag = false; //n秒内flag值为false,不触发计时器
}

</script>

</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>
    <style>
       body{
        height: 10000px;
    }
    </style>
</head>
<body>
</body>
<script>
 window.onscroll = throttle(task, 500)
 
//业务逻辑
function task(){
    console.log('触发');
}
//节流函数
//封装一个名为throttle,且返回值为函数的节流函数,来替代window.onscroll后承接的内容。因为返回值为函数,所以用闭包思想来实现封装
//节流函数里传入业务逻辑fn()和延迟时间delay初始化标记变量flag,值为true,优化全局变量flag,time,把变量time作为私有变量放入throttle函数中
function throttle(fn,delay){
    var flag = true;
    var time = null;
   // 组装业务逻辑函数和防抖函数
    return function(){
        if(flag){
            time = setTimeout(() => {
                fn.call(this)// 注:此处需改变this指针,否则业务逻辑中的this指向window
                flag = true;
            }, delay)
        }
        flag = false;
    }
}

</script>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值