WPF开发中的防抖和节流

2023-12-22 15:38:07 浏览数 (1)

前言

假如我们有一个上线用户的界面,每个用户上线的时候都会做一定的业务处理和页面刷新。

这样如果在短时间内用户大量进入就会导致页面处理不过来,而产生未响应甚至闪退。

这就要用到防抖和节流了。

它们都用在事件频繁触发并且允许丢失的场景下。

防抖和节流都是为了防止事件频发触发的一种方式。

函数防抖(debounce)

当持续触发某事件时,一定时间间隔内没有再触发事件时,事件处理函数才会执行一次,如果设定的时间间隔到来之前,又一次触发了事件,就重新开始延时。 可以保证最后的事件一定触发,但是可能中间可能新事件一直有,则一直取消触发。

函数节流(throttle)

当持续触发事件时,有规律的每隔一个时间间隔执行一次事件处理函数。 可以保证事件流中稳定的触发事件,但是不能保证最后的事件一定被触发。

函数防抖(debounce)

针对用户上线的场景适用防抖更加合适。

在 C# 页面渲染中,防抖处理通常用于限制用户频繁触发某个操作(如按钮点击、输入框输入等)时的请求或处理次数,以提高系统性能和用户体验。

不带参数

页面内的渲染方法基本上都不是静态的,并且参数可以使用页面的私有参数,方法本身不用传参数。

页面中

代码语言:javascript复制
private readonly Action _renderPage;
public AttendanceWindow()
{
    //页面初始化时初始化防抖对象
    _renderPage = new ZDebounceUtil().Create(RenderUserList, TimeSpan.FromSeconds(0.5));
}

private void RenderUserList()
{
    Dispatcher.Invoke(
        () =>
        {
            //UI渲染
        }
    );
}

//频繁触发的方法
public void UserListChange()
{
    //原来调用RenderUserList()改成如下
    _renderPage?.Invoke();
}

工具类

ZDebounceUtil.cs

代码语言:javascript复制
using System;
using System.Threading;

public class ZDebounceUtil
{
    private Timer _timer;
    private Action _action;
    private TimeSpan _timeout;

    private void DebouncedAction()
    {
        _timer?.Dispose();
        _timer = new Timer(
            state =>
            {
                _action();
            },
            null,
            _timeout,
            TimeSpan.FromMilliseconds(-1)
        );
    }

    public Action Create(Action action, TimeSpan timeout)
    {
        _action = action;
        _timeout = timeout;
        return DebouncedAction;
    }
}

带参数示例

下面是一个示例代码,

代码语言:javascript复制
static void Main(string[] args)
{
    Action<string> renderPage = new Debounce<string>().Create(RenderUserList, TimeSpan.FromSeconds(0.5));

    // 模拟用户频繁触发页面渲染的情况
    for (int i = 1; i <= 10; i  )
    {
        renderPage.Invoke($"Page {i}");
    }

    // 防抖处理后,只会执行最后一次调用
    // 输出:Page 10
}

static void RenderUserList(string pageName)
{
    Console.WriteLine($"Rendering {pageName}...");
    // 实际的页面渲染逻辑
}

防抖工具类

代码语言:javascript复制
using System;
using System.Threading;

public class Debounce<T>
{
    private Timer _timer;
    private Action<T> _action;

    public Action<T> Create(Action<T> action, TimeSpan timeout)
    {
        _action = action;
        return DebouncedAction;
        void DebouncedAction(T param)
        {
            _timer?.Dispose();
            _timer = new Timer(
                state =>
                {
                    _action(param);
                },
                null,
                timeout,
                TimeSpan.FromMilliseconds(-1)
            );
        }
    }
}

在此示例中,我们定义了一个名为 Debounce<T> 的通用类。

通过调用 Create 方法,我们可以创建一个经过防抖处理的函数。

当调用 renderPage.Invoke(pageName) 时,会在指定的时间间隔内只执行最后一次调用。

Render 方法中,我们模拟了实际的页面渲染逻辑,你可以根据实际情况进行修改。

函数节流(throttle)

不带参数

页面中

代码语言:javascript复制
private readonly Action _renderPage;
public AttendanceWindow()
{
    //页面初始化时初始化节流对象
    _renderPage = new ZThrottleUtil().Create(RenderUserList, TimeSpan.FromSeconds(0.5));
}

private void RenderUserList()
{
    Dispatcher.Invoke(
        () =>
        {
            //UI渲染
        }
    );
}

//频繁触发的方法
public void UserListChange()
{
    //原来调用RenderUserList()改成如下
    _renderPage.Invoke();
}

工具类

ZThrottleUtil.cs

代码语言:javascript复制
using System;
using System.Threading;

public class ZThrottleUtil {
    private Timer _timer;
    private Action _action;
    private TimeSpan _timeout;

    private void ThrottleAction()
    {
        if (_timer != null)
        {
            return;
        }
        _timer = new Timer(
            state =>
            {
                _action();
                _timer?.Dispose();
                _timer = null;
            },
            null,
            _timeout,
            TimeSpan.FromMilliseconds(-1)
        );
    }

    public Action Create(Action action, TimeSpan timeout)
    {
        _action = action;
        _timeout = timeout;
        return ThrottleAction;
    }
}

0 人点赞