Skip to content

GitHub 源码fast_debounce/fast_throttle/fast_rate_limit/

概览

基于 dart:async Timer 的静态工具类,用于控制高频触发的副作用(如按钮连点、搜索框输入、滚动回调)。三者均通过 tag 区分不同业务场景,互不干扰。

工具行为概要典型场景
FastDebounce连续触发时不断推迟;静默期结束后只跑最后一次搜索联想、窗口 resize
FastThrottle每个节流窗口至多执行一次(窗口首调立即执行,窗内其余调用丢弃提交按钮、点赞
FastRateLimit首调立即执行并开启按 duration 划分的时间窗;窗内再调不立刻执行,只合并为一份延后回调,在下一窗起点补跑搜索词合并提交、滚动分页加载

FastDebounce

FastDebounce 在每次调用时重置静默计时器;仅在连续 duration 内没有新调用时,才执行 onExecutedurationDuration.zero 时立即执行并清理已有计时器。

基础使用示例

搜索框:停输后再请求,避免每个字符都调接口。

dart
TextField(
  onChanged: (keyword) {
    FastDebounce.debounce(
      tag: 'search-suggest',
      duration: const Duration(milliseconds: 300),
      onExecute: () => fetchSuggestions(keyword),
    );
  },
);

// 页面销毁时取消未完成的防抖
@override
void dispose() {
  FastDebounce.cancel('search-suggest');
  super.dispose();
}
dart
void onKeywordChanged(String keyword) {
  FastDebounce.debounce(
    tag: 'search-suggest',
    duration: const Duration(milliseconds: 300),
    onExecute: () => fetchSuggestions(keyword),
  );
}

void dispose() {
  FastDebounce.cancel('search-suggest');
}

完整 API 参考


FastDebounce.debounce

连续触发时不断推迟执行,只在静默期结束时运行最后一次传入的 onExecute

dart
FastDebounce.debounce(
  tag: 'search-suggest',
  duration: const Duration(milliseconds: 300),
  onExecute: () {
    // 静默期结束后执行
  },
);
参数类型必填说明
tagString防抖实例标识。相同 tag 共用一条计时链;不同业务请分开命名(如 'search-suggest')。
durationDuration静默等待时长。每次再调都会重置计时;连续 duration 内无新调用才执行 onExecute。为 Duration.zero立即执行并清掉已有计时器。
onExecutevoid Function()静默期结束后执行的副作用(typedef:FastDebounceVoidCallback)。

FastDebounce.fire

不等静默期结束,立刻执行当前为该 tag 缓存的 onExecute(例如用户点「立即搜索」)。
fire 不会关闭已为该 tag 安排的静默计时器:若之后不再有新的 debounce 调用,静默期仍会到期,onExecute再执行一次。若你希望「只立刻跑这一次、静默到期时不要再跑」,请在同 tag 上先 fire、再 cancel

dart
FastDebounce.fire('search-suggest');

// 只立刻执行,且避免静默到期后再执行一次:
FastDebounce.fire('search-suggest');
FastDebounce.cancel('search-suggest');
参数类型必填说明
tagString要立刻执行的防抖实例标识。

FastDebounce.cancel

取消指定 tag 的计时器并移除内部记录;尚未触发的 onExecute 不会再执行。页面 dispose 时建议调用,避免泄漏或离页后仍回调。

dart
FastDebounce.cancel('search-suggest');
参数类型必填说明
tagString要取消的防抖实例标识。

FastDebounce.cancelAll

一次性取消所有进行中的防抖(例如全局登出、重置应用状态时)。

dart
FastDebounce.cancelAll();

无参数。


FastDebounce.count

查询当前仍处在「等待静默期」的防抖数量,便于调试或监控。

类型说明
返回值int(getter)仍在计时中的防抖实例个数。

FastThrottle

FastThrottle 为同一 tag 维护一个节流窗口(长度 duration)。窗口的首调立即执行 onExecute;窗口内的后续调用不会执行(返回值 skipped == true)。窗口结束后可选执行 onAfter

基础使用示例

提交按钮:连点只触发一次下单。

dart
FilledButton(
  onPressed: () {
    FastThrottle.throttle(
      tag: 'checkout-submit',
      duration: const Duration(seconds: 1),
      onExecute: () => placeOrder(),
    );
  },
  child: const Text('确认下单'),
);
dart
void submitOrder() {
  FastThrottle.throttle(
    tag: 'checkout-submit',
    duration: const Duration(seconds: 1),
    onExecute: () => placeOrder(),
  );
}

完整 API 参考


FastThrottle.throttle

为同一 tag 维护一个固定长度的节流窗口:窗口首调立刻执行 onExecute,窗内重复调用直接丢弃。

dart
final skipped = FastThrottle.throttle(
  tag: 'checkout-submit',
  duration: const Duration(seconds: 1),
  onExecute: () => placeOrder(),
  onAfter: () {}, // 可选
);
// skipped == true:仍在节流窗口内,本次被丢弃
// skipped == false:新窗口已开始,并已执行 onExecute
参数类型必填说明
tagString节流实例标识。同一 tag 在同一时刻最多只有一个活跃窗口。
durationDuration节流窗口长度。窗内再次调用不会延长窗口,只会被忽略。
onExecutevoid Function()进入新窗口时的首调回调,会立即执行(typedef:FastThrottleVoidCallback)。
onAftervoid Function()?窗口结束(计时器到期)时执行;例如恢复按钮可点状态。
返回值类型说明
truebool建议命名为 skipped:本次落在已有窗口内,执行 onExecute
falsebool刚开启新窗口,并已立刻执行 onExecute

FastThrottle.cancel

取消指定 tag 的节流窗口与计时器;该窗口内尚未触发的 onAfter不会再执行。

dart
FastThrottle.cancel('checkout-submit');
参数类型必填说明
tagString要取消的节流实例标识。

FastThrottle.cancelAll

取消全部进行中的节流。

dart
FastThrottle.cancelAll();

无参数。


FastThrottle.count

查询当前仍处于活跃节流窗口内的实例数量。

类型说明
返回值int(getter)进行中的节流实例个数。

FastRateLimit

FastRateLimit 用固定步长 duration 划分时间窗(内部为 Timer.periodic)。同一 tag限流进行中时,会维护一份 延后回调(窗内多次调用只保留最后一次传入的 onExecute / onAfter)。

行为说明

  1. 首调(该 tag 当前没有进行中的限流):立刻执行本次 onExecute,并启动按 duration 划窗的定时器;返回 false
  2. 窗内再调立刻执行;用本次传入的回调替换延后回调;返回 true
  3. 下一窗起点(定时器触发):若存在延后回调,则执行它及其 onAfter,然后清空;若上一个时间窗内没有任何「窗内再调」,则结束限流,并可能执行首调时传入的 onAfter

FastThrottle 的区别:节流在窗内丢弃多余调用;速率限制在窗内合并为「下一窗起点执行最新一次逻辑」。

基础使用示例

列表触底:合并短时间内的多次加载请求。

dart
void _onNearBottom() {
  FastRateLimit.rateLimit(
    tag: 'feed-load-more',
    duration: const Duration(milliseconds: 500),
    onExecute: () => loadNextPage(),
  );
}
dart
void onNearBottom() {
  FastRateLimit.rateLimit(
    tag: 'feed-load-more',
    duration: const Duration(milliseconds: 500),
    onExecute: () => loadNextPage(),
  );
}

完整 API 参考


FastRateLimit.rateLimit

首调立刻执行并开启按 duration 划分的时间窗;窗内再调不立刻跑,只把最新一次回调存为延后回调,在下一窗起点补跑(详见上文 行为说明)。

dart
final deferred = FastRateLimit.rateLimit(
  tag: 'feed-load-more',
  duration: const Duration(milliseconds: 500),
  onExecute: () => loadNextPage(),
  onAfter: () {}, // 可选
);
// deferred == true:限流进行中,本次已合并到下一窗
// deferred == false:首调(或限流结束后的重新开始),已立刻执行 onExecute
参数类型必填说明
tagString限流实例标识。相同 tag 共享同一份延后回调与划窗定时器。
durationDuration每个时间窗的长度(划窗步长)。
onExecutevoid Function()业务回调(typedef:FastRateLimitCallback)。首调时立即执行;窗内再调时只更新延后回调,在下一窗起点执行最后一次写入的版本。
onAftervoid Function()?与延后回调配对:对应 onExecute 跑完后调用同一次传入的 onAfter;若整窗无再调导致限流结束,可能执行首调时传入的 onAfter
返回值类型说明
truebool建议命名为 deferred:限流仍在进行,本次已合并到下一窗,立刻执行 onExecute
falsebool首调或限流已结束后的重新开始:已立刻执行 onExecute 并开启限流。

FastRateLimit.cancel

取消指定 tag 的划窗定时器并移除记录;尚未在下一窗执行的延后回调不会再跑。

dart
FastRateLimit.cancel('feed-load-more');
参数类型必填说明
tagString要取消的限流实例标识。

FastRateLimit.cancelAll

取消全部进行中的速率限制。

dart
FastRateLimit.cancelAll();

无参数。


FastRateLimit.count

查询当前仍在限流进行中(划窗定时器仍在运行)的实例数量。

类型说明
返回值int(getter)进行中的限流实例个数。

基于 MIT 许可证发布