JS进阶 | 关于防抖

192 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

一、什么是防抖

防抖:当用户触发某个事件的操作过于频繁,只执行最后一次对事件的操作。

其中包含几个要点:

  • 持续触发事件
  • 设置n秒的延时器,n秒内未触发,事件处理函数才会执行一次
  • 如果在n秒内触发了,则重新计时

一般防抖会和节流进行对比记忆:

节流:当持续触发事件时,n秒内只调用一次事件处理函数,在这段时间内不会重新执行事件。

应用场景

防抖:

  1. 按钮(比如提交表单表单、登录、上传、点赞等操作)
  2. 远程模糊搜索(当用户停止输入后再调取接口数据,而非输入一个字母搜索一次)
  3. 浏览器窗口尺寸变化、scroll等

实现

  • 我们可以认为防抖是闭包的实际应用

  • 当浏览器尺寸发生变化,window.onresize不断的调整大小,使用防抖函数来避免发生不断重排与重绘的问题

  • 实现:

    原函数:

    window.addEventListener('resize', ()=>{
        console.log(document.documentElement.clientWidth)
    })
    

    防抖后:

    (Fn: 回调函数, delay:延迟执行的时间)

    function debounce(Fn, delay){
        var timer = null;
        return function(){
            if(timer !== null){
                clearTimeout(timer);
            }
            timer = setTimeout(Fn,delay);
        }
    }
    
    function getWidth(){
        console.log(document.documentElement.clientWidth); // 屏幕尺寸
    }
    
    window.addEventListener("resize",debounce(getWidth,1000));
    
    

实现步骤详解:

  1. 首先通过闭包缓存一个定时器timer,初始值设为null
  2. 将 debounce 处理结果作为函数返回
  3. 如果已经设定过定时器,清空上一次的定时器
  4. 设定一个新的定时器,重新开始计时,当定时器结束后执行传入的函数getWidth(),也就是我们进行防抖后最终要的那个函数

这种方式的缺点是:无法在第一次触发回调事件时就执行,需要等待定时器执行完毕之后才会执行事件

升级版防抖

在原版的基础上,改造debounce函数:增加了immediate参数,true表示立即执行。

当设为立即执行模式时,如果定时器为空,直接执行一次事件

function debounce(Fn, delay,immediate){
    var timer = null;
    return function(){
        if(timer !== null){
            clearTimeout(timer);
        }
        if(immediate && !timer) {
            Fn.apply(this)
        }
        timer = setTimeout(Fn,delay);
    }
}