记录防抖和节流

记录所学,检验自己的掌握程度。

我们会遇到这样的场景,
一个按钮,正常逻辑是点击一次,等待接口返回数据,进行接下来的处理,
不小心一下次点了两次,就可能会造成提交两次的情况,接下来有了一堆bug,,,
我们来用防抖来尽可能的规避掉这个问题:

//  接收三个参数 1 需要防抖的函数 
//  2 第一次点击到第二次点击的间隔小于 多久 会触发防抖
//  3 第一次是否需要立即执行函数

function debounce(fn, wait,...args){
    let timer;
    return function(){
        let context = this;
        /* 使用闭包 来判断当前微任务队列是否有 fn
        在微任务队列 如果有就清除微任务队列的 fn */
        if(timer) clearTimeout(timer);
        //  在微任务队列添加事件
        timer = setTimeout(() => {
            fn.call(context, args);
        }, wait || 1000);
    }
}
复制代码

顺便整下节流
节流一个我能理解的应用场景就是 图片懒加载
判断图片是否处于可视区域,
这里先不实现,仅实现个节流的函数
和防抖类似

时间戳版本

function throttle(fn, wait,args){
    /*
        基本思路是:当调用节流函数时返回一个函数,
        这个时候记录了一个时间戳(prev),
        当触发节流函数返回的函数的时候,记录另一个时间戳,
        当两个时间戳大于我们定义的 wait的时候,
        就调用函数,这个时候改变prev函数
    */
    let prev = Date.now();
    return function(){
        let context = this;
        let current = Date.now();
        if(current - prev >= wait){
            fn.call(context, [...arguments]);
            //  改变prev的值 重新计时
            prev = current;
        }
    }
}
复制代码

定时器版本

function throttle (func, wait, ...args) {
  let timeout;
  /*
      思路:当timeout有值的时候,就忽略掉func函数的处理
      定时器到时,调用回调函数的时候,timout =null,调用func,
      为第一次调用函数,
      当timeout == null的时候,就启动一个定时器,
      微任务队列中注入函数func,
      如此循环往复
  */
  return function(){
    const context = this;
    if(!timeout){
      timeout = setTimeout(() => {
        timeout = null;
        func.apply(context,args);
      },wait)
    }
  }
}
复制代码

推荐阅读 防抖和节流原理分析,我的这篇记录也是由此而来,

把防抖和节流,做成Vue自定义指令,版本:2.6.11
同时来回忆下Vue官网自定义指令

// 防抖指令

const debounce = {
    inserted:function(el, binding){
        console.log(el, binding);
        let timer;
        let fn = binding.value;
        let opts = binding.arg[0],time = binding.arg[1] || 1000
        el.addEventListener('click',function(){
            if(timer) clearTimeout(timer);
            timer = setTimeout(() => {
                fn(opts);
            }, time);
        })
    }
}
export default debounce;
复制代码

PS: 如果仅仅是为防止按钮多次点击,有比上述防抖指令更优雅的解决方案,
比如:在指令里边直接令按钮不可点击,当逻辑处理好后,放开按钮,
这里防抖仅仅只是其中一种,~~

节流指令

const throttle = {
    inserted:function(el, binding){
        let prev = Date.now();
        let fn = binding.value;
        let opt = binding.arg[0],time = binding.arg[1] || 1000
        el.addEventListener('click',function(){
            let current = Date.now();
            if(current - prev > time){
                fn(opt);
                prev = current;
            }
        })
    }
}
复制代码

使用

// iview的框架
<Button v-debounce:[[arg1,2000]]="logFunc" type="primary">连续点击</Button>
复制代码

推荐阅读 分享8个非常实用的Vue自定义指令

记录所学,加深自己的理解,欢迎指出错误之处~~

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享