细说防抖与节流~~

46 阅读2分钟

说到防抖和节流大家肯定都不陌生啦,今天来分享一个较为完善的防抖与节流代码,可选触发立即执行delay之后再执行两种不同的情况。

1. 定义

先来回顾一下防抖和节流的定义:

  • 防抖:触发事件n秒后执行,在n秒内重复触发,则重新计时
  • 节流:n秒内只执行一次,在时间段内重复触发,不重复执行

like......⬇ 图片

2. 代码实现

  • 防抖: 根据防抖的定义,这里可以用到定时器+闭包初步实现:
function debounce(fn, delay) {    
    let timer;    
    return function (...args) {        
    if (timer) clearTimeout(timer); // 判断 timer 是否为 null        
    timer = setTimeout(() => {            
        fn.apply(this, args)        
    }, delay)    
}}

   可以看到,函数每次都会在delay后执行,如果我们需要首次触发事件上一次执行delay秒后触发事件让函数立即执行,而不必先等delay秒呢? 需要传入immediate变量控制是否立即执行:

function debounce(fn, delay, immediate = false) {    
    let timer;    
    return function (...args) {        
        if (timer) clearTimeout(timer);        
        if (immediate) {            
            let isCall = !timer; // 如果 timer 为 null 或 undefined 则触发立即调用
            if (isCall) fn.apply(this, args);            
            timer = setTimeout(() => {                
                timer = null;            
            }, delay)        
        } else {            
            timer = setTimeout(() => {                
                fn.apply(this, args)            
            }, delay)        
        }    
   }
}
  • 节流:根据节流的定义,这里同样可以用到定时器+闭包初步实现:
    function throttle(fn, delay) {    
        let timer = null;    
        return function (...args) {        
            if (!timer) {            
                timer = setTimeout(() => {                
                    fn.apply(this, args);               
                    timer = null;            
                }, delay)        
            }    
        }
    }

同样如果我们需要delay秒内让函数立即执行,而不必等delay秒呢?需要传入immediate变量控制是否立即执行,同时我们新增节流取消函数cancel

    function throttle(fn, delay, immediate = true) {
        let timer = null;
        return {
            func: function (...args) {
                if (!timer) {
                    if (immediate) {
                        fn.apply(this, args);
                        timer = setTimeout(() => {
                            timer = null
                        }, delay)
                    } else {
                        timer = setTimeout(() => {
                            fn.apply(this, args);
                            timer = null;
                        }, delay)
                    }
                }
            },
            cancel: function () {
                clearTimeout(timer);
                timer = null;
            }
        }
    }

3. 应用场景

  1. 防抖
  • 搜索框搜索输入,用户最后一个字符输入完特定延迟后,再发送请求    
  • 窗口大小resize,窗口调整完成后再计算窗口大小,防止重复渲染
  1. 节流
  • 按钮快速点击事件,如多次快速点击表单提交按钮,防止频繁重复提交    
  • 鼠标移动事件监听,鼠标移动事件会高频触发,监听鼠标移动并实现实时绘制图形、动态更新元素样式等,可固定时间进行一次更新   
  • 窗口滚动事件监听,同理也会高频触发,如果在每次滚动事件触发时都去执行相应的业务逻辑(比如检查图片是否进入可视区域来懒加载),会对浏览器性能造成较大压力

end~