5 分钟搞懂防抖与节流

205 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,点击查看活动详情

前言

防抖与节流是前端优化高频执行代码的一种有效手段,常见的应用场景有输入框查询,浏览器各种事件(例如滚动)的回调等等,可以使用防抖和节流来进行性能优化,当然他也是前端面试的常见考题之一,废话不多,开始今天的学习

简介

通常提到防抖和节流,和将它们拿在一起进行对比,这里先看他们的定义

  • 防抖(debounce) : n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
  • 节流(throttle) : n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

实际上他们对应的是两种完全不同的场景,相同点可以说它们都是对高频执行场景的优化,不同点的话,从代码执行层面讲,防抖是规定时间内如果重复触发会一直推迟,最后执行一次,节流是重复触发的话,在规定的时间间隔内只执行一次

防抖

应用场景

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

思路

防抖的实现思路就是延迟函数和闭包的应用,这里的timer计时器就是内部变量,通过判断timer是否存在把上一次的执行动作取消,最终只执行最后一次

代码实现

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

节流

应用场景

  • 滚动加载,加载更多或滚到底部监听

思路

节流的实现思路主要是对时间间隔(频率)的控制,记录好事件发生的时间,后续连续触发时拿当前时间和记录的时间作比较,如果时间间隔大于频率时间则执行方法,并更新时间,如果小于则不做处理

代码实现

function throttle (fn, threshhold) {
    let timer
    return function () {
        const curTime = new Date()
        if (timer) {
            if (curTime - timer > threshhold) {
                fn()
                timer = curTime
            } 
        } else {
            timer = curTime
            fn() // 看是否需要立即执行一次
        }
    }
}

传参改良

到这大部同学应对防抖节流的实现没有什么疑问了,可能有些基本功不扎实的同学会疑问如果我们要在返回的方法传参怎么做,也很简单,用我们apply绑定一下就好啦

  • 防抖传参
function debounce (fn, delay) {
    let timer
    return function (...args) {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            fn.apply(this, args)
        }, delay)
    }
}
  • 节流传参
function throttle (fn, threshhold) {
    let timer
    return function (...args) {
        const curTime = new Date()
        if (timer) {
            if (curTime - timer > threshhold) {
                fn()
                timer = curTime
            } 
        } else {
            timer = curTime
            fn.apply(this, args) // 看是否需要立即执行一次
        }
    }
}

这个地方实际是一个rest参数(...args)apply的结合应用,理解了这点,传参也就很简单啦~