防抖和节流的抽象比喻实现

95 阅读2分钟

v2-809a23dd4cd0de81fcf03baf240827a3_r.jpg

防抖和节流是js中常用的两种性能优化方式,他们能减少函数的执行次数以及提高代码的性能

防抖

  • 防抖是指连续多次触发同一事件,只执行最后一次或者最开始时执行一次。防抖的应用场景比较广泛,例如用户搜索关键词时,可以使用防抖来避免频繁的发起请求

  • 也可以这样理解防抖:回城被打断或者回城嘲讽,玩过王者农药的朋友都知道,回城技能大概要站着不动3秒左右才能释放,中途不能移动或者按别的按键。

    • 防抖也是,特别像你把对面英雄打死了,一直点回城一直点回城嘲讽他似的
    • 一直点回城一直点回城(除了原地抽搐啥也干不了,当然这里是不会抽搐的),除非你点了回城后不再动了,你才能回城成功。
    • 防抖就是,你一直执行某个事件,一直执行某个事件,你是执行不了的,只有你最后一次执行它了,不再执行了,那么它才会触发

下面是简单的防抖实现代码

注: 函数名和变量名都用中文代替,方便理解

function 回城() {
    console.log('我要回城,你打我呀')
}

设置一个定时器,因为回城有时间的嘛
let timer = null

function 释放回城() {
    // 如果存在回城时间,那它肯定刚刚点了回城,得刷新回城时间
    if (timer) {
        clearTimeout(timer)
    }
    timer = setTimeout(() => {
        // 执行回城
        回城()
        // 定时器清空,毕竟都回城了,要它干嘛
        timer = null
    }, 3 * 1000)
}

很好,这样就写好了一个防抖代码了

那么我们不能只有回城防抖呀,别的技能也要防抖呢,我们封装一下

function 防抖函数(技能, 执行时间) {
    let timer = null
    return function() {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            // 执行技能
            技能()
            timer = null
        }, 执行时间)
    }
}

把中文变量名改成英文名,再加个技能参数吧

    function debounce(fn, delay) {
        let timer = null
        
        return function(...arg) {
            if (timer) {
                clearTimeout(timer)
            }
            timer = setTimeout(() => {
                fn(...arg)
                timer = null
            }, delay)
        }
    }

以下是用户搜索关键词时时使用防抖的例子

<input type="text" id="searchInp">

<script>
    const searchInp = document.getElementById('searchInp')
    
    function search(keyword) {
        console.log(`搜索关键词是: ${keyword}`)
        .....
    }
    // 先执行防抖函数, 插入一个定时器,返回一个新的函数
    const debounceSearch = debounce(search, 600)
    
    searchInp.addEventListener('input', e => {
        // 每次输入都会执行新的函数,看看有没有定时器
        debounceSearch(e.target.value)
    })
</script>

节流

  • 理论: 节流是指多次连续触发同一事件,每隔一定时间触发一次。例如在用户滚动页面时,可以使用节流来避免频繁地触发函数。

  • 可以这样理解节流: 王者中的闪现冷却是120秒,当闪现用完后的这120秒中是用不了的,120秒冷却过后才能继续用。所以节流是不是可以理解为技能冷却时间

以下是实现节流的代码

注: 函数名和变量名都用中文代替,方便理解

// 定义一个闪现的技能
function 闪现() => {
    console.log('我闪我闪我闪闪闪!!!')
}
// 定义一个技能是否冷却的变量
let 冷却中 = false

// 定义一个释放技能的函数,如果当前处于冷却,那么技能释放不了,return。如果不在冷却,
// 那么释放闪现,冷却变成true,然后定个定时器,120秒后冷却中改成false,又可以用闪现了

function 释放技能() {
    if (冷却中) return
    闪现()
    冷却中 = true
    // 定义一个计时器
    setTimeout(() => {
        冷却中 = false
    }, 120 * 1000)
}


这个其实就是节流的代码

那么我们要实现某个技能的节流,并不单单只是闪现的,怎么做呢?

那就定义一个函数,把技能和冷却时间放进去不就好了

function 技能控制函数(技能, 冷却时间) {
    let 冷却中 = false

    return function() {
        if (冷却中) return
        技能()
        冷却中 = true
        setTimeout(() => {
            冷却中 = false
        }, 冷却时间)
    }
}

这不就很完美了嘛,当然,在我们的代码中最好不要用中文变量名,并且技能万一有参数呢,也要传一传

function throttle(fn, time) {
    let cd = false
    
    return function(...arg) {
        if (cd) return
        fn(...arg)
        cd = true
        setTimeout(() => {
            cd = false
        }, time)
    }
}

以上就是一个完美的节流的方法拉

调用方式如下:

const huicheng(name) {
    console.log(`我是 ${name}, 没血了快回城别浪`)
}
const shifang = throttle(huicheng, 90 * 1000) 

shifang('典韦')

防抖和节流的使用场景

防抖和节流的应用场景比较广泛,可以在很多具体功能中使用它们来提高代码的性能。例如:

  • 在用户输入搜索关键词时,可以使用防抖来避免频繁地向服务器发送请求。
  • 在监听窗口大小改变时,可以使用防抖来避免频繁地调整布局。
  • 用户频繁的点击按钮时,比如抢购,可以使用节流来避免频繁地触发函数