谈一下防抖和节流吧,拿来把你~

524 阅读4分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

函数的防抖和节流

我们自己规定频繁触发的条件[例如:我们规定300ms内,只要触发两次就是频繁]

  防抖:防止“帕金森”,在频繁触发的模式下,我们只识别一次[识别第一次,也可以识别最后一次]

  节流:降低触发的频率,他能识别“多次”[浏览器有自己的最快反应时间,例如:谷歌57ms IE 1017ms,

      这样在我们的疯狂操作下,谷歌浏览器的频率是5ms执行一次,节流是降低这个频率,比如我们设定频率是300ms,

     在疯狂触发的时候,我么能控制间隔300ms才让其执行一次]

一般点击事件以防抖为主 [但是有些需求也是节流]

  键盘输入事件 或者 滚动条滚动事件 都是以节流为主

防抖

动作绑定事件,动作发生后一定时间后触发事件,在这段时间内,如果该动作又发生,则重新等待一定时间再触发事件。

具体方法是:在上一次事件触发之后的 time 时间内如果事件没有再次触发,那么就在 time 时间后触发,否则将触发的时间作为新的起始点

通俗理解就是,将密集的时间触发事件看作一个时间整体,整个整体只触发一次事件,密集的界定就是相邻事件触发时间小于 time,则以这个整体的最后一次事件触发为起始点

function debounce(func, time) {
  let timer = null;
  return () => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, arguments);
    }, time);
  };
}

使用闭包的原因 原因是 timer 变量是在 debounce 函数内部初始化的时候声明的,但是之后每一次触发返回的箭头函数的时候都需要读取 timer 变量,所以要使用闭包

节流

动作绑定事件,动作发生后一段时间后触发事件,在这段时间内,如果动作又发生,则无视该动作,直到事件执行完后,才能重新触发。

节流和防抖大致相同,不同点在于:

  • 防抖是“随机应变”,以密集的事件触发处的末尾为下一次事件触发的计时开始处
  • 节流是“铁打不动”,始终以第一次事件触发为起始点,忽略 time 时间内的所有事件,第一次事件发生 time 事件之后触发第二次事件

在数轴上理解的相同点和区别为:

[2, 5] 时间内触发的所有事件都浓缩为一次事件,区别是:防抖将此次事件的发生事件定在最后一次事件触发的时间,节流将时间定在第一次事件触发的时间

function throtte(func, time) {
  let activeTime = 0;
  return () => {
    const current = Date.now();
    if (current - activeTime > time) {
      func.apply(this, arguments);
      activeTime = Date.now();
    }
  };
}

上一个代码分析

let box = document.querySelector('.box'// debounce:函数防抖
// @params 
//      func [function,required]:最后要执行的函数
//      wait:[number]设定的频繁触发的频率事件,默认值是300
//      immediate:[boolean]设置是否在开始边界触发,默认值是false
// @return 
//      func执行返回结果
//  update 2021/08/25 by quanquan

function debounce(func,wait,immediate){
    if(typeof func!== "function"throw new TypeError('func must be required and be an function')
    if(typeof wait==="boolean"){
        immediate = wait;
        wait = 300;
    }
    if(typeof wait !== "number") wait = 300;
    if(typeof immediate!== "boolean") immediate = false

    var timer = null;
    return function proxy(){
        if(timer)  clearTimeout(timer);
        timer = setTimeout(function(){
            if(timer){
                clearTimeout(timer);
                timer = null;
            }
            func();
        },wait)    
    }
}


// 第一次点击 0 
//  设置定时器 -> 300ms
// 第二次点击 5ms
//  把之前设定的定时器干掉 
//     设置一个新的 设置定时器 -> 300ms
//  第三次点击 5ms
//    ......  
// 一直到设定一个新的定时器,但是在300ms内没有触发第二次



// 模拟获取数据

function queryData(callback){
    setTimeout(() =>{
        typeof callback === "function" ? callback('OK') : null;
    },1000)
}


function fn() {
    console.log('OK')
}
box.onclick = debounce(fn,300,true)
// box.onclick = proxy 疯狂点击box,疯狂触发proxy,但是我们最终想执行的是fn,
// 所以需要我们在proxy中,基于一些逻辑的处理,让fn只执行一次


// let isRun = false;
// box.onclick = function(){
//     if(isRun) return ;
//     isRun = true
//     // console.log('点我干啥!')
//     queryData(result => {
//         console.log(result)
//         isRun = false
//     })
// }

此类文章持续迭代更新中,请持续关注吧。

最后来个小广告,最近突发奇想想见一个高质量前端技术交流群,目前群里有网易、百度、字节大佬,欢迎入群,一起学习。

微信群.jpg

前端路漫漫其修远兮,吾将上下而求索,一起加油,学习前端吧

欢迎留言讨论~