throttle与debouce

315 阅读2分钟

点击按钮打开一个页面,但是按钮点击一次页面打开两次,如何处理?

我们肯定会想到节流与防抖函数,这两个函数很像,到底有什么区别呢?

如果这么写:

onClick = _.throttle(()=>{
    openNextPage();
}, 3000);

或者

onClick = _.debounce(()=>{
    openNextPage();
}, 3000);

一个按钮快速点击10次,上面两种写法会发生什么? 会存在哪些问题?

防抖 debounce

第一次点击开始计时,中间有重复触发,则倒计时重置,倒计时结束后触发

适用不想重复的场景,某段时间内只执行一次: 比如点击

节流 throttle

第一次点击触发,设定时间内的重复触发都被抛弃

比如:按钮点击、resize window

适用想重复(每隔N秒)但是不想太频繁的场景,固定频率

比如:用户输入的验证、scroll触发、resize window

手写防抖

functuon debounce(fn, wait){
    let timer = null;
    
    return function(){
        let context = this;
        let args = arguments;
        
        // 重复触发则重置
        if(timer){
            clearTimeout(timer);
            timer = null;
        }
        
        // 设置定时器
        timer = setTimeout(()=>{
            fn.apply(context, args);
        }, wait);
    }
}

手写节流

function throttle(fn, time){
    let curTime = Date.now();
    
    return function(){
        let context = this;
        let args = arguments;
        let nowTime = Date.now();
        
        if(nowTime - curTime >= time){
            curTime = Date.now();
            return fn.apply(context, args);
        }
    }
}
    

场景1:

onClick = _.throttle(()=>{
    openNextPage();
}, 3000);

Q: 一个按钮快速点击10次,会发生什么? 会存在哪些问题?

A: 立即执行,然后3s后再执行一次

场景2:

onClick = _.debounce(()=>{
    openNextPage();
}, 3000);

Q: 一个按钮快速点击10次,会发生什么? 会存在哪些问题?

A: 每次点击都会重新计时,计时结束后才会执行打开下一页的操作,所以打开下一页的时间是大于3s的(最后一次点击开始计时)

场景3:

onClick = _.debounce(()=>{
    openNextPage();
}, 
3000,
{leading: true, tailing: false});

Q: 一个按钮快速点击10次,会发生什么? 会存在哪些问题?

A: 立即执行一次,后面的点击到导致不断重复计时,只有最后一次点击3秒后才能执行

点击防抖到底应该怎么做

如果是未知原因的点击一次,响应两次,可以设置wait为500ms

onClick = _.debounce(()=>{ 
    openNextPage(); 
}, 500);

如果是防止快速点击,设置1s即可,但是要加leading:true,保证先执行

onClick = _.debounce(()=>{ 
    openNextPage(); 
}, 
1000, 
{leading: true, tailing: false}
);