JS性能优化——防抖(debouncing)和节流(throttle)

182 阅读5分钟

前言

其实这篇也是来自我的一篇笔记,看正好对青训营的要求就在笔记的基础上拓展拓展,来简单讲讲JS性能优化之防抖(debouncing)和节流(throttle)🥶

基础知识

  • 防抖🌳🍃:适用于处理用户停止频繁操作后的事件执行,例如输入框内容变动的场景。
  • 节流🌊🧱:适用于控制高频事件的触发频率,例如滚动、窗口调整等场景。

都是为了优化性能,防止不必要的重复操作或过多的资源消耗。

防抖(Debounce)

防抖的作用是减少频繁触发事件,确保只有最后一次操作得到执行。防抖适用于那些用户可能会频繁触发的操作,但我们只关心最后一次操作结果的场景。

举例来说,在处理搜索框输入时,每次用户键入一个字符都会触发搜索请求,可能会导致大量不必要的网络请求。通过防抖技术,可以让搜索请求在用户停止输入一段时间后才执行,避免了频繁的请求。

实现上,防抖通过计时器 setTimeout 来实现。如果在规定时间内用户再次触发了该事件,计时器就会被重置,只有当用户停止操作超过设定的时间时,计时器才会执行回调函数。

代码示例

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

const handleInput = debounce(function() {
    console.log('Input processed:', this.value);
}, 500);

document.querySelector('input').addEventListener('input', handleInput);

节流(Throttle)

节流的作用是控制高频事件的触发频率,使得在一段时间内只能执行一次。节流适用于那些可能会频繁触发的操作,但我们希望在特定时间间隔内控制执行次数的场景。

举例来说,在处理页面滚动事件时,每次滚动都会触发事件,如果不加以控制,可能会导致性能问题。通过节流技术,可以限制滚动事件的处理频率,例如每隔500毫秒处理一次。

实现上,节流可以通过标志位(flag)来控制函数的执行。函数在第一次执行后,会设置一个标志位阻止后续的执行,直到设定的时间间隔过去,再重置标志位以允许下一次执行。

代码示例

function throttle(fn, delay) {
    let flag = true;
    return function() {
        if (flag) {
            flag = false;
            setTimeout(() => {
                fn.apply(this, arguments);
                flag = true;
            }, delay);
        }
    };
}

const handleScroll = throttle(function() {
    console.log('Scroll event processed');
}, 500);

window.addEventListener('scroll', handleScroll);

防抖(Debouncing)和节流(Throttling)是处理高频率事件(如滚动、输入等)时常用的两种技术。它们可以提高性能并避免重复触发事件。

最佳实践

在实际开发中,选择防抖还是节流需要根据具体场景的特点和需求进行权衡。以下是一些常见的最佳实践:

何时使用防抖(Debounce)?

  1. 搜索框输入
    用户输入时,每次变动都可能触发请求或耗时操作。通过防抖,确保只在用户完成输入后(如500ms后)再触发事件。

  2. 调整窗口大小(resize)
    当用户频繁调整窗口时,某些回调(如重新计算布局)可能会触发多次。通过防抖,可以减少多余的计算。

  3. 表单验证
    实时验证用户输入内容,但不希望在用户每次键入时立即触发验证,可以使用防抖延迟验证。

何时使用节流(Throttle)?

  1. 页面滚动(scroll)
    滚动事件触发频率极高,但多数场景下只需要定期更新内容(如滚动加载数据)或触发某些操作(如显示/隐藏导航栏)。节流可以限制触发频率。

  2. 按钮点击
    防止用户快速多次点击按钮造成重复提交或重复事件。

  3. 鼠标移动事件(mousemove)
    在需要绘图或跟随鼠标的动画场景中,通过节流减少计算次数以提升性能。

结合使用防抖和节流

在某些场景中,可以结合两者的优点。例如,在页面滚动加载数据时:

  • 使用节流控制滚动事件触发频率,减少性能开销。
  • 同时对加载操作应用防抖,确保滚动停止后执行更重的操作(如预加载更多内容)。

通用优化建议

  1. 合理设置时间间隔
    时间间隔的选择直接影响用户体验。防抖时间过短可能导致效果不明显,过长则可能造成延迟响应。节流间隔过短可能降低优化效果,过长则可能丢失用户操作。

  2. 考虑业务优先级
    对于影响较大的操作,如表单提交、搜索建议,应优先使用防抖减少无效操作。对于性能开销高的场景(如滚动加载),应优先使用节流。

  3. 测试与调优
    不同设备性能差异可能导致相同时间间隔表现不同,应测试并优化以确保跨设备一致性。

工具库

在实际项目中,为了避免重复实现这些功能,可以使用成熟的工具库,如 Lodash,提供了易用的 debouncethrottle 方法:

import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';

// 使用 Lodash 实现防抖
const handleInput = debounce((event) => {
    console.log('Input processed:', event.target.value);
}, 500);

// 使用 Lodash 实现节流
const handleScroll = throttle(() => {
    console.log('Scroll event processed');
}, 500);

document.querySelector('input').addEventListener('input', handleInput);
window.addEventListener('scroll', handleScroll);

通过实践与优化,防抖和节流可以显著提升用户体验和应用性能。

后记

我也忘记我当初是看到什么文章去了解这俩东西的,目前没在项目中用到过🫠,我就是菜,娜扎辣😁。