MST

星途 面试题库

面试题:React 列表事件处理中的防抖与节流策略

假设在 React 应用中有一个可滚动的长列表,列表项上绑定了滚动事件处理函数,当滚动到某个列表项时触发特定操作,但频繁触发会导致性能问题。请详细说明如何使用防抖(Debounce)和节流(Throttle)策略来优化这种情况。分别阐述防抖和节流的原理,给出在 React 中实现它们的自定义 Hook 代码,并说明在这种场景下它们各自的优缺点。
34.7万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

防抖(Debounce)

  1. 原理:防抖是指在事件触发后的一定时间内(防抖时间),如果再次触发该事件,会重新计算时间,直到设定的时间内没有再次触发,才执行回调函数。简单来说,就是将多次操作合并为一次操作,延迟执行。
  2. React 中自定义 Hook 实现
import { useCallback, useRef } from 'react';

const useDebounce = (callback, delay) => {
    const timer = useRef();

    return useCallback((...args) => {
        if (timer.current) {
            clearTimeout(timer.current);
        }
        timer.current = setTimeout(() => {
            callback.apply(this, args);
        }, delay);
    }, [callback, delay]);
};

export default useDebounce;
  1. 优点:可以有效减少函数执行次数,适用于一些频繁触发但不需要立即响应的场景,如窗口 resize、输入框输入等,能显著提升性能。
  2. 缺点:如果防抖时间设置过长,可能会导致用户操作和响应之间出现明显延迟,影响用户体验。

节流(Throttle)

  1. 原理:节流是指在一定时间内(节流时间),无论事件触发多少次,都只会执行一次回调函数。它可以控制函数在一定时间间隔内只被调用一次,从而限制函数的执行频率。
  2. React 中自定义 Hook 实现
import { useCallback, useRef } from'react';

const useThrottle = (callback, delay) => {
    const lastCallTime = useRef();

    return useCallback((...args) => {
        const now = new Date().getTime();
        if (!lastCallTime.current || now - lastCallTime.current >= delay) {
            callback.apply(this, args);
            lastCallTime.current = now;
        }
    }, [callback, delay]);
};

export default useThrottle;
  1. 优点:在保证一定响应频率的同时,避免了函数的过度调用,能在一定程度上平衡性能和响应速度。适用于一些需要频繁触发且需要即时反馈的场景,如滚动事件、鼠标移动事件等。
  2. 缺点:由于节流时间固定,即使在节流时间内事件触发很频繁,也只能执行一次回调,可能无法精确满足某些对响应及时性要求极高的场景。

在可滚动长列表场景中的应用

在 React 应用的可滚动长列表场景中,将滚动事件处理函数用防抖或节流进行包装:

import React, { useEffect } from'react';
import useDebounce from './useDebounce';
import useThrottle from './useThrottle';

const LongList = () => {
    const handleScrollDebounce = useDebounce(() => {
        // 滚动到某个列表项时触发的特定操作
        console.log('Debounce: 执行特定操作');
    }, 300);

    const handleScrollThrottle = useThrottle(() => {
        // 滚动到某个列表项时触发的特定操作
        console.log('Throttle: 执行特定操作');
    }, 300);

    useEffect(() => {
        window.addEventListener('scroll', handleScrollDebounce);
        return () => {
            window.removeEventListener('scroll', handleScrollDebounce);
        };
    }, [handleScrollDebounce]);

    useEffect(() => {
        window.addEventListener('scroll', handleScrollThrottle);
        return () => {
            window.removeEventListener('scroll', handleScrollThrottle);
        };
    }, [handleScrollThrottle]);

    return (
        <div style={{ height: '100vh', overflowY: 'auto' }}>
            {/* 长列表内容 */}
        </div>
    );
};

export default LongList;

根据具体需求选择防抖或节流,如果对响应及时性要求不高,希望最大程度减少函数执行次数,可选择防抖;如果需要一定频率的即时反馈,避免过度调用,可选择节流。