防抖和节流的理解,及其应用场景

01****概 念

**目的:**当多次执行某一动作,进行函数调用次数的限制,节省资源

**防抖:**在事件触发n秒后执行函数,如果在n秒内再次出发,重新计时

**节流:**当多次执行某一动作,每隔一段时间,只执行一次函数。

区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。

比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

( 简要回答 )

**防抖:**防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零

**节流:**控制流量,单位时间内事件只能触发一次,如果服务器端的限流即 Rate Limit。代码实现重在开锁关锁

02

应用场景

函数防抖的应用场景

连续的事件,只需触发一次回调的场景有:

  • 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求
  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测(change、input、blur、keyup等事件触发,每次键入都会触发)
  • 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
  • 鼠标的mousemove、mouseover
  • 导航条上,用户不停的在导航区域滑动相当于

函数节流的应用场景

间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚到底部监听,window.onscroll和滑到底部自动加载更多
  • 谷歌搜索框,搜索联想功能
  • 高频点击提交,表单重复提交

03

防抖的实现

防抖函数(普通)

 1var timer; //全局的timer,只有一个
 2function debounce(fn,delay){
 3    if(timer){
 4        clearTimeout(timer) //保证只开启一个定时器
 5    }
 6    timer = setTimeout(function(){
 7        fn(); //延迟delay,执行函数
 8    },delay)
 9}
10window.onscroll = function(){
11    debounce(test,1000)
12}
13function test(){
14    console.log('滚动停')
15}

需要将timer封装到debounce中,如果调用的fn有参数需要处理

 1function debounce(fn,delay){
 2    let timer;
 3    return function(){
 4        let _this = this; //为了改写参数 保存this 应用apply
 5        let _args = arguments; //保存testDebounceFn的入参
 6        if(timer){
 7            clearTimeout(timer);
 8        }
 9        timer = setTimeout(function(){
10            //apply传参正好和arguments匹配
11            fn.apply(_this,_args)
12        },delay)
13    }
14}
15let testDebounceFn = debounce(test,1000);
16function test(a){
17    console.log('滚动停 '+a)
18}
19window.onscroll = function(){
20    testDebounceFn('aaaa')
21}

04

节流的实现

节流(2种方式setTimeout 或者 new Date()) 防抖比节流严格,防抖在一定时间操作后只执行一次。节流在一定时间操作,可每隔n秒执行一次

setTimeout方式

 1function throttle(fn,delay){
 2    let timer;
 3    return function(){
 4        let _args = arguments;
 5        let _this = this;
 6        if(timer){//如果有定时器,退出
 7            return
 8        }
 9        timer = setTimeout(function(){
10            fn.apply(_this,_args);//定时器结束执行函数
11            timer = null;//清除定时器,可以再次进入
12        },delay)
13    }
14}
15let testThrottleFn = throttle(test,3000);
16function test(a){
17    console.log('打印 '+a)
18}
19window.onscroll = function(){
20    testThrottleFn('bbbb')
21}

new Date方式

 1function throttle(fn,delay){
 2    let previous = 0;
 3    return function(){
 4        let _this = this;
 5        let _argus = arguments;
 6        let now = new Date();
 7        //不同时间取值的new Date()是可以相减的
 8        if(now-previous>delay){
 9            fn.apply(_this,_argus);
10            previous = now;
11        }
12    }
13}
14let testThrottleFn = throttle(test,2000);
15function test(b){
16    console.log('出现 '+b)
17}
18window.onscroll = function(){
19    testThrottleFn('8888')
20}
个人笔记记录 2021 ~ 2025