/// 🔧 防抖和限流工具类 - 用于处理快速点击导致的重复请求 /// /// 使用场景: /// 1. 防抖(Debounce):用户快速点击按钮,等用户停止点击后再执行一次 /// - 模式切换、搜索、自动保存 /// 2. 限流(Throttle):在给定时间内最多执行一次 /// - 节点切换、数据刷新、VPN 启动/停止 import 'dart:async'; import 'package:get/get.dart'; class KRDebounceThrottleUtil { // 防抖计时器缓存(防止多个防抖冲突) static final Map _debounceTimers = {}; // 限流时间戳缓存 static final Map _throttleTimestamps = {}; /// 🔧 防抖函数:等待 delay 时间无新请求后才执行 /// /// 适用于:模式切换、搜索、自动保存等 /// /// 例子: /// ```dart /// KRDebounceThrottleUtil.debounce( /// key: 'mode_switch', /// delay: Duration(milliseconds: 300), /// action: () { /// controller.kr_updateConnectionType(newType); /// }, /// ); /// ``` static void debounce({ required String key, required Duration delay, required VoidCallback action, }) { // 如果有旧的待执行任务,取消它 _debounceTimers[key]?.cancel(); // 设置新的延迟任务 _debounceTimers[key] = Timer(delay, () { action(); _debounceTimers.remove(key); }); } /// 🔧 异步防抖函数(支持 Future) /// /// 适用于需要等待异步操作的场景 /// /// 例子: /// ```dart /// await KRDebounceThrottleUtil.debounceAsync( /// key: 'node_switch', /// delay: Duration(milliseconds: 500), /// action: () async { /// await controller.kr_performNodeSwitch(tag); /// }, /// ); /// ``` static Future debounceAsync({ required String key, required Duration delay, required Future Function() action, }) async { _debounceTimers[key]?.cancel(); return Future.delayed(delay).then((_) async { await action(); _debounceTimers.remove(key); }); } /// 🔧 限流函数:在指定时间内最多执行一次 /// /// 返回值:true 表示执行成功,false 表示被限流(仍在冷却中) /// /// 适用于:节点切换、数据刷新、VPN 启动/停止等频繁操作 /// /// 例子: /// ```dart /// final canExecute = KRDebounceThrottleUtil.throttle( /// key: 'refresh', /// duration: Duration(seconds: 2), /// ); /// /// if (canExecute) { /// await controller.kr_refreshAll(); /// } else { /// showToast('操作过于频繁,请稍后再试'); /// } /// ``` static bool throttle({ required String key, required Duration duration, }) { final now = DateTime.now(); final lastExecuteTime = _throttleTimestamps[key]; // 如果这是第一次执行或已经过了冷却时间 if (lastExecuteTime == null || now.difference(lastExecuteTime).inMilliseconds >= duration.inMilliseconds) { _throttleTimestamps[key] = now; return true; // 允许执行 } return false; // 仍在冷却期,拒绝执行 } /// 🔧 异步限流函数 /// /// 返回值:true 表示执行成功,false 表示被限流 /// /// 例子: /// ```dart /// final success = await KRDebounceThrottleUtil.throttleAsync( /// key: 'node_switch', /// duration: Duration(milliseconds: 2000), /// action: () async { /// await controller.kr_performNodeSwitch(tag); /// }, /// ); /// ``` static Future throttleAsync({ required String key, required Duration duration, required Future Function() action, }) async { if (throttle(key: key, duration: duration)) { try { await action(); return true; } catch (e) { // 如果执行失败,重置时间戳以允许重试 _throttleTimestamps.remove(key); rethrow; } } return false; } /// 🔧 获取某个 key 的剩余冷却时间(毫秒) /// /// 返回值: /// - 0 或负数:可以执行 /// - 正数:还需等待的毫秒数 static int getRemainingThrottleTime({ required String key, required Duration duration, }) { final lastExecuteTime = _throttleTimestamps[key]; if (lastExecuteTime == null) return 0; final remaining = duration.inMilliseconds - DateTime.now().difference(lastExecuteTime).inMilliseconds; return remaining > 0 ? remaining : 0; } /// 🔧 清除指定 key 的所有计时器(调试用) static void clear({String? key}) { if (key != null) { _debounceTimers[key]?.cancel(); _debounceTimers.remove(key); _throttleTimestamps.remove(key); } else { // 清除所有 for (var timer in _debounceTimers.values) { timer.cancel(); } _debounceTimers.clear(); _throttleTimestamps.clear(); } } /// 🔧 获取防抖和限流的统计信息(调试用) static Map getStats() { return { 'activeDebounces': _debounceTimers.keys.toList(), 'activeThrottles': _throttleTimestamps.keys.toList(), 'totalActiveTimers': _debounceTimers.length + _throttleTimestamps.length, }; } } /// 🔧 防抖辅助类 - 用于在 Controller 中创建防抖版本的方法 /// /// 例子: /// ```dart /// class MyController extends GetxController { /// late final _debouncer = KRDebouncedMethod( /// key: 'mode_switch', /// delay: Duration(milliseconds: 300), /// ); /// /// void kr_updateConnectionType(KRConnectionType type) { /// _debouncer.call(() async { /// // 实际的业务逻辑 /// }); /// } /// } /// ``` class KRDebouncedMethod { final String key; final Duration delay; KRDebouncedMethod({ required this.key, this.delay = const Duration(milliseconds: 300), }); void call(VoidCallback action) { KRDebounceThrottleUtil.debounce( key: key, delay: delay, action: action, ); } Future callAsync(Future Function() action) async { return KRDebounceThrottleUtil.debounceAsync( key: key, delay: delay, action: action, ); } void cancel() { KRDebounceThrottleUtil.clear(key: key); } } /// 🔧 限流辅助类 - 用于在 Controller 中创建限流版本的方法 /// /// 例子: /// ```dart /// class MyController extends GetxController { /// late final _throttler = KRThrottledMethod( /// key: 'refresh', /// duration: Duration(seconds: 2), /// ); /// /// void kr_refreshAll() { /// if (_throttler.canExecute()) { /// // 执行刷新逻辑 /// } /// } /// } /// ``` class KRThrottledMethod { final String key; final Duration duration; KRThrottledMethod({ required this.key, required this.duration, }); bool canExecute() { return KRDebounceThrottleUtil.throttle(key: key, duration: duration); } Future executeAsync(Future Function() action) async { return KRDebounceThrottleUtil.throttleAsync( key: key, duration: duration, action: action, ); } int getRemainingTime() { return KRDebounceThrottleUtil.getRemainingThrottleTime( key: key, duration: duration, ); } void reset() { KRDebounceThrottleUtil.clear(key: key); } }