JavaScript:防抖和节流,你了解过吗?

JavaScript:防抖和节流

一、防抖

  • 定义:出发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次发生,则重新计算时间。

  • 实现思路:每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法;

  • 缺点:如果事件在规定的时间间隔内不断被触发,则调用方法会不断地被延迟。

// 简易版
function debounce(fn){
    
    
    let timeout = null;
    return function(){
    
    
        clearTimeout(timeout);
        timeout = setTimeout(()=>{
    
    
            fn.apply(this,arguments);
        },1000);
    }
}

function handle(){
    
    
    console.log(this);
}

window.onmousemove = debounce(handle);
  • 简易版有个缺点:当调用事件时,this对象永远指向window(因为在闭包中),因此,我们可以在闭包中先将上下文存储起来;
// 高级版
function debounce(func, wait, immediate){
    
    
    var timeout, result;   
    let decounced = function(){
    
    
        //改变内部this指向
        let context = this;
        let args = arguments;
        clearTimeout(timeout);
        if(immediate){
    
    
            let callNow = !timeout;
            timeout = setTimeout(() => {
    
    
                timeout = null;
            }, wait);
            //表示立即执行
            if(callNow) result = func.apply(context, args);

        }else {
    
    
            //不会立即执行
            timeout = setTimeout(function(){
    
    
                result = func.apply(context, args);
            }, wait);
        }
        return result;
    }
    decounced.cancel = function(){
    
    
        clearTimeout(timeout);
        timeout = null;
    }
    return decounced;
}

function handle(){
    
    
    console.log(this);
}

window.onmousemove = debounce(handle,1000,true);

二、节流

  • 定义:高频事件触发,但是在n秒内只会执行一次,过亿节流会稀释函数的执行频率;
  • 实现思路:当事件触发时,如果当前有等待执行的延时函数,直接return;
// 简易版
function throttle(fn){
    
    
    let canRun = true;
    return function(){
    
    
        if(!canRun) return;
        canRun = false;
        setTimeout(()=>{
    
    
            fn.apply(this,arguments);
            canRun = true;
        },1000);
    }
}

function handle(){
    
    
    console.log(Math.random());
}

window.onmousemove = throttle(handle);
  • 同样的问题,简易版this指向window;
// 高级版
// options传入一个对象,表示模式
//{
    
    
//	leading : true/false,
// 	trailing : true/false
//}
function throttle(fn,wait,options){
    
    
    let context,args,timeout,result;
    let old = 0;
    if(!options) options = {
    
    };
    
    
    let throttled = function(){
    
    
        context = this;
        args = arguments;
        let later = function(){
    
    
            old = new Date().valueOf();
            timeout = null;
            result = fn.apply(context,this);
        }
        
        let now = new Date().valueOf();
        if(options.leading === false && !old){
    
    
            old = now;
        }
        if(now - old > wait){
    
    
            //头部执行
            if(timeout){
    
    
                clearTimeout(timeout);
                timeout = null;
            }
            result = fn.apply(context,args);
            old = now
        }else if(!timeout && options.trailing !== false){
    
    
            //尾部执行
            timeout = setTimeout(later,wait);
        }
        return result;
    }
    
    
    throttled.cancel = function(){
    
    
        clearTimeout(timeout);
        old = 0;
        timeout = context = args = null;
    }

    return throttled;
}
function handle(){
    
    
    console.log(Math.random());
}

window.onmousemove = throttle(handle,1000,{
    
    
	leading : true,
	trailing : false
});

三、区别

  • 节流不管事件触发多么频繁,都保证在规定时间内一定会执行一次事件函数;
  • 防抖只是在最后一次事件才触发一次函数;

四、适用场景

  • 防抖
  1. scroll事件滚动触发,比如设置什么时候出现 回到顶部 的图标
  2. 搜索框输入查询,当用户输入完停顿时再进行搜索(模糊搜索)
  3. 表单验证,当用户输入完停顿时再进行实时检测
  4. 按钮提交事件,防止暴力点击发送多次请求
  5. 浏览器窗口缩放,resize事件
  • 节流
  1. DOM元素的拖拽功能的实现
  2. 射击游戏
  3. 计算鼠标移动的距离
  4. 监听scroll滚动事件

猜你喜欢

转载自blog.csdn.net/yivisir/article/details/108041603