防抖、节流

106 阅读2分钟

防抖

概念

持续触发事件,规定时间内没有再次触发,执行一次,规定时间内再次触发,重新开始延时,只会响应一次触发

代码实现

非立即执行---只响应最后一次----input框输入搜索

        const debounce  = function (delay,cb){
            // 下一次触发,需要取消上一次的timer,所以需要保留上一次的timer,使用闭包实现
            let timer
            return function(value){
                // 存在timer,取消并开启一个新的
                if(timer){
                    clearTimeout(timer)
                }
                timer = setTimeout(()=>{
                   cb(value)
                },delay)
            }
        }

立即执行----只响应第一次----表单提交或点击按钮发起请求

        const debounceImmediate  = function(delay,cb){
            let timer
            return function(value){
                let isFirst = !timer
                if(isFirst){
                    cb(value)
                }
                if(timer){
                    clearTimeout(timer)
                }
                timer = setTimeout(()=>{
                  timer = null
                },delay)
            }
        }

案例演示:

    <h1>非立即执行版本案例</h1>
    搜索:<input id="input"/>
    <hr>
    <h1>立即请求版本案例</h1>
    <button id="btn">提交</button>
        // input输入实时搜索
        const inputFn = function(value){
            console.log(`发起请求,搜索key为${value}`)
        }
        let inputDebounce = debounce(1000,inputFn)
        document.querySelector('#input').addEventListener('input',(event)=>{
            inputDebounce(event.target.value)
        })
        
        // 点击按钮提交表单
         const btnFn  = function(){
            console.log('正在提交表单')
        }
        let btnDebounce = debounceImmediate(1000,btnFn)
        document.querySelector('#btn').addEventListener('click',btnDebounce)

image.png

应用场景

  1. 点击按钮发送请求时,需要使用debounce来防止用户疯狂点击按钮造成重复提交请求
  2. 页面resize
  3. search搜索联想,节约请求资源

节流

概念

持续触发事件,保证在规定时间内,只执行一次事件处理函数,时间间隔内,响应一次触发,控制频率

代码实现

借助定时器实现

  const throttle = function(delay,cb){
            let timer
            return function(){
                // timer 存在不做任何处理
                if(timer) return 
                timer = setTimeout(() => {
                    cb()
                    // 执行完毕后恢复timer初始值
                    timer =null
                }, delay);
            }
        }

还可以借助时间戳来实现

        const throttleByTime = function(delay,cb){
            let time 
            // 是否第一次触发标识--为了保证第一次执行回调函数是在第一次点击后的delay毫秒时刻
            let first = true
            return function(){
            // 第一次点击,选取当前时间赋值给time
                if(first){
                    time = Date.now()
                    first = false
                }
                if(Date.now()-time>=delay){
                    time = Date.now()
                    cb()                  
                }
            }
        }

案例演示:

    <style>
    .father{
        width:300px;
        height:30px;
        background-color:green;
    }
    .son{
        height:100%;
        width:0;
        background-color: red;
    }
    </style>
    
    <div class="father">
        <div class="son"></div>
    </div>
    <button id="btn">增加进度</button>
        let sonDiv = document.querySelector('.son')
        const btnFn  = function () {
            let currentWidth = sonDiv.style.width.split('%')[0]
            if(currentWidth<100){
                sonDiv.style.width =Number(currentWidth)+5+'%'
            }    
            console.log(currentWidth)  
        }
        let fn = throttleByTime(1000,btnFn)
        document.querySelector('#btn').addEventListener('click',fn)

截屏2023-06-26 17.50.54.png 点击一次按钮,进度增加5%,但是使用节流处理后,不管你手速多快,也只会一秒执行一次函数,增加5%,难道这就是我抢不到演唱会门票的原因吗?

应用场景

  1. 监听滚动事件
  2. input实时搜索