yx_async_throttle_flutter/lib/async_throttle.dart

80 lines
2.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:easy_debounce/easy_debounce.dart';
import 'package:easy_debounce/easy_throttle.dart';
/// 异步防抖/节流工具类
class AsyncThrottle {
// 私有构造函数,防止外部实例化
AsyncThrottle._();
// 懒汉式单例 - 使用 late final 延迟初始化
static final AsyncThrottle _instance = AsyncThrottle._();
// 获取单例实例
static AsyncThrottle get instance => _instance;
// 存储异步任务锁状态
final Map<String, bool> _asyncLocks = {};
/// 异步执行方法 - 防止弱网重复点击 (无 Loading UI)
///
/// 结合了 时间策略(防抖/节流)和 异步任务状态锁。
/// 只有当满足以下两个条件时才会执行:
/// 1. 当前没有正在执行的同名任务 (Task Lock - 解决弱网长耗时问题)
/// 2. 满足时间策略 (Time Policy - 解决快速连点问题)
///
/// [tagId]: 唯一标识符
/// [onExecute]: 要执行的异步方法
/// [duration]: 时间间隔,默认 300ms
/// [enableDebounce]: 是否启用防抖模式。
/// - true: 使用防抖 (Debounce) - 延迟执行,最后一次点击生效(适合搜索、输入)
/// - false: 使用节流 (Throttle) - 立即执行,忽略后续点击(默认,适合按钮点击)
Future<void> execute(
String tagId,
Future<void> Function() onExecute, {
Duration duration = const Duration(milliseconds: 300),
bool enableDebounce = false,
}) async {
// 1. 检查异步锁 (防止上一个请求未回来时重复点击)
// 无论是防抖还是节流,只要任务还在执行中,都不应重入
if (isExecuting(tagId)) return;
if (enableDebounce) {
// === 防抖模式 (Debounce) ===
// 延迟 duration 后执行,如果在期间再次调用,会重新计时
EasyDebounce.debounce(tagId, duration, () async {
// 防抖触发时,再次检查锁(双重检查)
if (isExecuting(tagId)) return;
_asyncLocks[tagId] = true;
try {
await onExecute();
} finally {
_asyncLocks.remove(tagId);
}
});
} else {
// === 节流模式 (Throttle) - 默认 ===
// 立即执行,并在 duration 内忽略后续调用
// throttle 返回 true 表示被节流忽略false 表示获得了执行权
final isThrottled = EasyThrottle.throttle(tagId, duration, () {});
// 如果被节流了,直接返回
if (isThrottled) return;
// 获得执行权,加锁并执行
_asyncLocks[tagId] = true;
try {
await onExecute();
} finally {
_asyncLocks.remove(tagId);
}
}
}
/// 检查任务是否正在执行
bool isExecuting(String tagId) => _asyncLocks[tagId] ?? false;
/// 强制取消所有锁(慎用)
void clearAllLocks() => _asyncLocks.clear();
}