这锅我背了......

本文介绍了防抖(debounce)和节流(throttle)两种技术,它们常用于优化前端表单提交、事件处理等场景,防止过度调用。防抖在事件频繁触发时,只在停止触发后的一段时间执行,而节流则是在设定时间内只执行一次。文中通过代码示例详细解释了两者的实现和区别,并提供了在线运行的链接。
摘要由CSDN通过智能技术生成

目录

  1. 防抖(debounce)
  2. 节流(throttle)
  3. 防抖和节流的区别

上周写了个表单,没仔细看Toast的遮罩配置,以为和之前一样都是默认开启的,然而实际上是被关了,又因为我偷懒没给按钮加防抖节流,于是出现了用户重复提交多条数据的情况…

默默掏出小本本记下究竟谁关了我的遮罩按钮 一定要记得加防抖节流!!!

好了,言归正传,来复习下防抖节流。

1、防抖

防抖,debounce。这个概念最早来自于相机,现在流行的相机防抖原理也分很多种,有镜头防抖、机身防抖等,我们代码里的防抖比较类似软件防抖:

“软件会持续地监测手的抖动情况:如果你的手正在抖动,这时候即便你已经摁下了快门手机也不会进行拍照,直到它监测到你忽然有一个瞬间手是比较静止的,诶!它就自动按下了快门!所以这个并不是什么主动的防抖功能,它只是主动选择了一个’手不抖的时间’拍照。这个功能适合拍风光,不适合拍人像,因为它没有办法抓拍。”[1]

相机抖动.gif

再举个生活中的防抖例子,坐过电梯的童鞋应该感受过,电梯总是要等一小段时间后再关门,如果在电梯门关上之前,又有人进入,那么电梯就会重新开门等一小段时间再关上。如果不断有人在电梯关闭前进入,电梯就会等最后一个人进来后,再等待一小段时间后才真正关门运行。

所谓防抖,就是在事件触发后延迟n秒再执行;如果在这n秒内再次触发该事件,则重新计时,延迟n秒后再执行。

代码实现:

function debounce(fn, delay) {
    let timer = null;
    return () = >{
        if (timer) {
            // 重新计时
            clearTimeout(timer);
        }
        const context = this;
        timer = setTimeout(() = >{
            fn.apply(context, arguments);
            clearTimeout(timer);
        },
        delay);
    }
}


let count = 0;
const play = debounce(() = >{
    console.log(count++);
},
3000);

在线运行:http://jsrun.net/Tr8Kp/edit

节流

节流,throttle。工程热力学术语释义:管道中流动的流体经过通道截面突然缩小的阀门、狭缝及孔口等部分后发生压力降低的现象称为节流。[2]

简单来讲,就是通过阀门限制实际流量。比如用户在10s内发起了1000次请求,节流控制后,实际上10s内,只有1次请求会被真正发送到服务器,其他请求都不会发出。

节流就是一段时间内,不论事件触发多少次,都只执行一次。

代码实现:

// 时间戳版本
function throttle(fn, delay) {
    let isRun = false;
    let startTime = Date.now();
    return function() {
        let now = Date.now();
        if (now - startTime > delay) {
            // 延迟执行
            // const context = this
            // fn.apply(context, arguments)
            startTime = now isRun = false;
        }


        if (isRun) return;


        isRun = true;


        // 立即执行
        const context = this 
        fn.apply(context, arguments)
    }
}

let count = 0;
const play = throttle(() = >{
    console.log(count++);
},
3000);

在线运行:http://jsrun.net/Wr8Kp/edit

// 定时器版本
function throttle(fn, delay) {
    let timer = null
    return () = >{
        if (timer) return;
        const context = this;
        // 立即执行
        fn.apply(context, arguments);
        timer = setTimeout(() = >{
            // 延迟执行
            // fn.apply(context, arguments);
            clearTimeout(timer);
            timer = null;
        },
        delay);
    }
}


let count = 0;
const play = throttle(() = >{
    console.log(count++);
},
3000);

在线运行:http://jsrun.net/Lr8Kp/edit

防抖和节流的区别

看看下面这段测试代码:

let t = 0;
/** 每隔一秒点一下,一直都不会触发,除非停止自动点击 */
let interval = null;
start();
function start() {
    if (!interval) {
        interval = setInterval(() = >{
            t++;
            console.log("触发" + t + "次");
            play();
        },
        1000);
    }
}


function stop() {
    console.log("点击了停止触发");
    clearInterval(interval);
    interval = null;
}

这段测试代码,每隔1秒会触发一次play()方法,按照上面防抖和节流的代码,delay都是3s的话,输出结果各是什么?

防抖debounce输出结果:

停止触发3s后才输出count=0

节流throttle输出结果:

理论上每隔3s输出一次count值,但实际上可能略大于3s,具体可了解下浏览器的宏任务微任务

区别:

  • 防抖因为一直不断被触发,每次触发都会重新计时,始终达不到3s的延迟,所以始终无法执行;只有在停止触发后才会执行(最后一次触发的3s后,输出count值0);
  • 而节流则每隔3s执行一次;3s内可能有多次触发,但这3s内只会执行一次。

参考资料:

[1] https://m.sohu.com/a/288759421_419981
[2] https://baike.baidu.com/item/节流/13128947?fr=aladdin
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值