提升前端效率:掌握防抖与节流

发布时间:2023年12月18日

目录

概念

代码实现

区别

应用场景


概念

当涉及到处理高频事件时,防抖(Debounce)和节流(Throttle)成为关键的工具。它们的作用是优化函数的执行频率,特别是在处理浏览器事件(如resize、scroll、keypress、mousemove等)时,有助于减少不必要的函数执行,提高前端性能和用户体验

节流(Throttle) 像是给事件加上了时间间隔。就像大厦底下的电梯,定时运行以确保在每个时间段内只执行一次。比如,在规定的时间间隔内(比如15秒),无论有多少人进入电梯,都只会在规定时间到达时运行一次。

防抖(Debounce) 则更像是“重置”计时器。当第一个人进入电梯后,等待一段时间(比如15秒),如果这段时间内有人再次进入,计时器会重新开始,直到等待时间耗尽后才会执行一次。

这两种策略都有助于控制函数的执行次数,优化性能,并可根据场景特性选择合适的策略。节流适用于需要在一段时间内定期执行的场景,而防抖则更适用于等待最后一个事件后再执行的场景。正确使用它们能有效减少资源消耗,改善用户体验,特别是在大规模的前端应用中。

代码实现

以下是节流的具体代码实现:

function throttled(fn, delay) {
    let timer = null
    let starttime = Date.now()
    return function () {
        let curTime = Date.now() // 当前时间
        let remaining = delay - (curTime - starttime)  // 从上一次到现在,还剩下多少多余时间
        let context = this
        let args = arguments
        clearTimeout(timer)
        if (remaining <= 0) {
            fn.apply(context, args)
            starttime = Date.now()
        } else {
            timer = setTimeout(fn, remaining);
        }
    }
}

这段代码是一个简单的基于时间戳的节流函数实现。它的目的是确保一个特定函数在设定的时间间隔内只执行一次。

首先,它接受一个需要执行的函数和一个时间间隔作为参数。在每次函数被调用时,它会记录当前时间戳并计算自上次执行以来的时间差。这段时间与设定的时间间隔进行比较:

如果时间间隔已经超过了设定的延迟,那么立即执行传入的函数,并更新上次执行的时间戳。如果时间间隔尚未达到设定的延迟,它会设置一个新的定时器,在剩余的时间后再次尝试执行函数。

以下是防抖的具体代码实现:

function debounce(func, wait) {
    let timeout;

    return function () {
        let context = this; // 保存this指向
        let args = arguments; // 拿到event对象

        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context, args)
        }, wait);
    }
}

这个函数接收一个需要执行的函数和一个等待时间作为参数。每当这个函数被调用时,它会清除之前设定的定时器,并设置一个新的定时器,在等待一段时间后执行传入的函数。

每次调用函数时,它会获取当前的 this 上下文和传入的参数。然后清除之前设置的定时器。接着,设置一个新的定时器,在指定的等待时间后执行传入的函数,并将之前获取的上下文和参数传递给这个函数。

防抖如果需要立即执行,可加入第三个参数用于判断,实现如下:

function debounce(func, wait, immediate) {

    let timeout;

    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout); // timeout 不为null
        if (immediate) {
            let callNow = !timeout; // 第一次会立即执行,以后只有事件执行后才会再次触发
            timeout = setTimeout(function () {
                timeout = null;
            }, wait)
            if (callNow) {
                func.apply(context, args)
            }
        }
        else {
            timeout = setTimeout(function () {
                func.apply(context, args)
            }, wait);
        }
    }
}

这个函数和之前的防抖函数类似,接收一个需要执行的函数、等待时间和一个布尔值 immediate 作为参数。但是它做了一些额外的处理以满足不同的需求。

首先,它仍然会获取当前的 this 上下文和传入的参数。然后,根据 immediate 参数的不同情况进行不同的处理:如果 immediatetrue,则在第一次调用时会立即执行函数,并且只有在等待时间后再次触发时才会重新计时延迟执行。如果 immediatefalse 或未提供,默认行为是等待一定时间后执行函数。

在代码中,它根据 immediate 参数的值设定一个 callNow 变量,用于控制第一次是否立即执行函数。如果是立即执行,并且是第一次调用,则会立即执行函数;否则,在等待时间后执行函数。

这种实现方式适用于需要在首次触发时立即执行一次函数的情况,之后再根据设定的间隔进行延迟执行。这样能够更加灵活地满足不同场景下的需求,比如处理搜索建议时立即展示结果,然后在用户停止输入后再次触发。

区别

防抖和节流都是用于控制函数执行频率的技术,但它们的核心思想和实现方式有所不同。

防抖的核心思想是确保在连续触发事件后,只有在最后一次触发后的一段时间内没有再次触发时才执行函数。换句话说,当函数被触发后,如果在指定的时间内再次触发,就会重新计时延迟执行。这可以避免在短时间内多次触发时导致函数过早执行。

节流的核心思想是确保函数在一定时间间隔内最多执行一次。它会稀释函数的执行频率,无论触发频率多高,函数都会按照规定的时间间隔执行一次。这可以有效减少函数的执行次数。

区别在于:

触发时刻不同: 防抖在最后一次触发后的一段时间内不再触发才执行函数,而节流则是按照一定的时间间隔执行函数。

执行次数不同: 防抖确保在延迟后执行一次,而节流在规定的时间间隔内执行一次。

举例来说,如果是处理输入框搜索建议,防抖会在用户输入停止后延迟一段时间再触发搜索;而节流则会每隔一定时间执行一次搜索,无论用户输入频率如何。

应用场景

防抖的应用场景:

1?? 输入框搜索建议: 在用户输入时,防抖可以延迟执行搜索操作,只有在用户停止输入一段时间后才触发实际的搜索请求,减少无效请求,提高搜索体验。

2?? 窗口大小调整: 当用户调整浏览器窗口大小时,防抖可用于延迟调整页面布局或重新计算元素大小,确保在用户停止调整窗口大小后才执行这些操作,避免频繁执行布局或计算操作。

3??? 按钮点击事件: 在按钮点击时,使用防抖可以避免用户多次点击造成的多次触发,确保只有在最后一次点击后的一段时间内没有再次点击时才执行操作,比如提交表单或打开新页面。

节流的应用场景:

1?? 页面滚动: 当用户滚动页面时,节流可以控制滚动事件的触发频率,以降低滚动事件的处理次数,提高页面性能。

2???鼠标移动事件: 在处理鼠标移动时,节流能够稀释函数的执行,保证在一定时间内只执行一次,避免过多的鼠标移动事件触发函数执行。

3?? 限制接口请求: 在某些场景下,例如用户频繁操作触发接口请求,节流可用于限制请求的频率,确保在一定时间间隔内只发送一次请求,避免服务器压力过大或节省用户的流量消耗。

好啦,本文就到这里啦!

文章来源:https://blog.csdn.net/weixin_51735748/article/details/135005559
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。