From 825aa8017d79b122acf3be485ad2cc88c0e342d3 Mon Sep 17 00:00:00 2001 From: "DESKTOP-I3JPKHK\\wy" <1111> Date: Fri, 12 Dec 2025 16:00:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=98=B2=E6=8A=96=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E5=85=A8=E9=83=A8=E6=89=A7=E8=A1=8C=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/async_throttle.dart | 49 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/async_throttle.dart b/lib/async_throttle.dart index 99f9250..0fad4bc 100644 --- a/lib/async_throttle.dart +++ b/lib/async_throttle.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:easy_debounce/easy_debounce.dart'; import 'package:easy_debounce/easy_throttle.dart'; @@ -15,6 +17,9 @@ class AsyncThrottle { // 存储异步任务锁状态 final Map _asyncLocks = {}; + // 存储防抖模式下的 Completer,确保被取消的任务能正确结束 await + final Map> _debounceCompleters = {}; + /// 异步执行方法 - 防止弱网重复点击 (无 Loading UI) /// /// 结合了 时间策略(防抖/节流)和 异步任务状态锁。 @@ -40,18 +45,37 @@ class AsyncThrottle { if (enableDebounce) { // === 防抖模式 (Debounce) === - // 延迟 duration 后执行,如果在期间再次调用,会重新计时 + + // 关键修复:检查是否有正在等待的防抖请求。 + // 如果有,说明它被本次新请求“顶掉”了(EasyDebounce 会取消上一个 Timer)。 + // 我们需要手动完成它,否则上一次的 await 将永远挂起,导致内存泄漏。 + if (_debounceCompleters.containsKey(tagId)) { + _completeDebounce(tagId); + } + + final completer = Completer(); + _debounceCompleters[tagId] = completer; + EasyDebounce.debounce(tagId, duration, () async { - // 防抖触发时,再次检查锁(双重检查) - if (isExecuting(tagId)) return; + // 双重检查:确保 Completer 还在(防止极端并发情况) + if (!_debounceCompleters.containsKey(tagId)) return; + + // 防抖触发时,再次检查锁 + if (isExecuting(tagId)) { + _completeDebounce(tagId); + return; + } _asyncLocks[tagId] = true; try { await onExecute(); } finally { _asyncLocks.remove(tagId); + _completeDebounce(tagId); // 任务结束,通知 await 返回 } }); + + await completer.future; } else { // === 节流模式 (Throttle) - 默认 === // 立即执行,并在 duration 内忽略后续调用 @@ -71,9 +95,26 @@ class AsyncThrottle { } } + /// 辅助方法:安全地完成并移除 Completer + void _completeDebounce(String tagId) { + if (_debounceCompleters.containsKey(tagId)) { + final completer = _debounceCompleters[tagId]; + if (completer != null && !completer.isCompleted) { + completer.complete(); + } + _debounceCompleters.remove(tagId); + } + } + /// 检查任务是否正在执行 bool isExecuting(String tagId) => _asyncLocks[tagId] ?? false; /// 强制取消所有锁(慎用) - void clearAllLocks() => _asyncLocks.clear(); + void clearAllLocks() { + _asyncLocks.clear(); + // 清理时把所有等待的 Future 也都释放掉,防止外部 await 永久挂起 + for (var key in _debounceCompleters.keys.toList()) { + _completeDebounce(key); + } + } }