javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript防抖节流

一文学会JavaScript如何手写防抖节流

作者:大眼睛图图

其实防抖和节流不仅仅在面试中会让大家手写,在实际项目中也可以起到性能优化的作用,所以还是很有必要掌握的。这篇文章就带大家彻底学会JavaScript手写防抖节流,希望对大家有所帮助

前言

记得当初看这篇大佬的文章一杯茶的时间,带你彻底学会手写防抖节流已经对防抖节流有了个清晰的认识,但那个时候由于真的是第一次接触到防抖节流,对它的手写方式还是很迷,卡在着卡了很久。

所以今天打算在那篇文章的基础上做一些补充,让小白对防抖节流的手写能够真正掌握。

防抖节流的概念

一个经典的比喻:

想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应

假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制

电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。

电梯第一个人进来后,15秒后准时运送一次,这是节流。

再举个不太严谨的比喻:

防抖:就是王者荣耀里的回城,一段时间内被打断,就又要重新计时。

节流:就是王者荣耀里英雄的技能,像东皇的大一般都是20s准时来一次。

手写

防抖

首先我们先简单的模拟一个按钮被点击的过程。

let addBtn=document.getElementById('add')
function addOne(){
  console.log('增加一个')
}
addBtn.addEventListener('click',addOne)

加入防抖功能

// debounce.js
let addBtn=document.getElementById('add')

function addOne(){
  console.log('增加一个')
}

function debounce(fun,time){
    setTimeout(()=>{
      fun()
    },time)
}
addBtn.addEventListener('click',debounce(addOne,2000))

现在延时的目的是达到了但是每次点击都会新增一个新的setTimeout而且并不能达到我们多次点击只执行一次的效果。

这时候就需要clearTimeout登场了,我们需要在我们点击了按钮后也就是debounce执行时要先把之前的setTimeout先清除再重新计时。

这时我们会很自然地想到这个写法:

function debounce(fun, time) {
    let timer;
    
     // 如果之前就存在定时器,就要把之前那个定时器删除
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(() => {
            fun()
        }, time)
    
}

但是这样写的话拿的到之前定时器的值吗?

当然是拿不到的,因为每次都会重新let timer,所以这个时候我们就要使用闭包(延迟了变量的生命周期)了。

如果你还不太理解闭包,可以参考这篇文章包教包会——作用域链+闭包

引入闭包后

function addOne(){
  console.log('增加一个')
}

function debounce(fun, time) {
    let timer;
    
    return function(){
     // 如果之前就存在定时器,就要把之前那个定时器删除
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(() => {
            fun()
        }, time)
        
    }
}

addBtn.addEventListener('click',debounce(addOne,2000))

这里还有一点需要知道的,每执行一次addEventListener,debounce因为返回的是一个函数,并结合addEventListener的特点,会直接执行debounce返回的函数,不会出现每次都let timer

function debounce(fun, time) {
    let timer;
    
    return function(){
     // 如果之前就存在定时器,就要把之前那个定时器删除
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(() => {
            fun.apply(this, arguments)
        }, time)
        
    }
}

这样一个防抖就写出来了

节流

// throttle.js
function scrollTest(){ 
    console.log('现在我触发了')
}

function throttle(fun,time){
  return function(){
    fun()
  }
}
document.addEventListener('scroll',throttle(scrollTest,3000))

这里用闭包是为了后面获得上一次的时间

// throttle.js
...
function throttle(fun,time){
  let t1=0 //初始时间
  return function(){
    let t2=new Date() //当前时间
    if(t2-t1>time){
      fun.apply(this,arguments)
      t1=t2
    }
  }
}

应用场景

防抖在连续的事件,只需触发一次回调的场景有:

节流在间隔一段时间执行一次回调的场景有:

到此这篇关于一文学会JavaScript如何手写防抖节流的文章就介绍到这了,更多相关JavaScript防抖节流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文