非重入混入Skill asyncredux-nonreentrant-mixin

NonReentrant混入是一种用于AsyncRedux库的技能,用于防止动作的并发执行,确保在动作运行期间,同一类型的动作不会被重复调度。这有助于避免重复表单提交、防止竞态条件和保护长时间运行的操作。关键词包括:非重入混入、AsyncRedux并发控制、动作调度防重复、Flutter开发优化。

移动开发 0 次安装 0 次浏览 更新于 3/19/2026

名称:asyncredux-nonreentrant-mixin 描述:添加NonReentrant混入以防止在动作已在运行时调度同一动作。涵盖防止重复表单提交、避免竞态条件和保护长时间运行的操作。

NonReentrant 混入

NonReentrant混入防止同一动作类型的并发执行。当动作实例已在运行时,相同动作的新调度会被静默中止。

基本用法

NonReentrant混入添加到任何不应并发运行的动作中:

class SaveAction extends AppAction with NonReentrant {
  Future<AppState?> reduce() async {
    await http.put('http://myapi.com/save', body: 'data');
    return null;
  }
}

使用此混入:

  • 如果用户快速多次点击“保存”,只有第一次调度执行
  • 当第一次运行时,后续调度会被静默中止
  • 不会发生重复API调用或竞态条件

工作原理

NonReentrant混入重写abortDispatch方法。当abortDispatch()返回true时,动作的before()reduce()after()方法不会运行,状态保持不变。

默认情况下,检查基于动作的运行时类型——同一动作类的多个实例不能同时运行。

常见用例

  1. 防止重复表单提交 - 阻止用户意外多次提交表单
  2. 保护API调用 - 确保保存/更新/删除操作不会并发执行
  3. 资源密集型任务 - 防止昂贵的计算并行运行
  4. 避免竞态条件 - 确保必须不重叠的操作顺序执行

自定义

允许不同参数并发运行

重写nonReentrantKeyParams()以允许具有不同参数的动作并行运行:

class SaveItemAction extends AppAction with NonReentrant {
  final String itemId;
  SaveItemAction(this.itemId);

  @override
  Object? nonReentrantKeyParams() => itemId;

  Future<AppState?> reduce() async {
    await saveItem(itemId);
    return null;
  }
}

使用此自定义:

  • SaveItemAction('A')SaveItemAction('B')可以并发运行
  • 两个SaveItemAction('A')的调度仍会相互阻塞

在不同动作类型之间共享键

重写computeNonReentrantKey()以使不同的动作类相互阻塞:

class SaveUserAction extends AppAction with NonReentrant {
  final String orderId;
  SaveUserAction(this.orderId);

  @override
  Object? computeNonReentrantKey() => orderId;

  Future<AppState?> reduce() async { ... }
}

class DeleteUserAction extends AppAction with NonReentrant {
  final String orderId;
  DeleteUserAction(this.orderId);

  @override
  Object? computeNonReentrantKey() => orderId;

  Future<AppState?> reduce() async { ... }
}

这防止SaveUserAction('123')DeleteUserAction('123')同时运行——当同一资源上的不同操作必须不重叠时很有用。

与其他混入组合

您可以将NonReentrant与其他兼容的混入组合:

class LoadDataAction extends AppAction with CheckInternet, NonReentrant {
  Future<AppState?> reduce() async {
    final data = await fetchData();
    return state.copy(data: data);
  }
}

不兼容的混入: NonReentrant不能与以下混入组合:

  • Throttle
  • UnlimitedRetryCheckInternet
  • 大多数乐观更新混入(检查兼容性矩阵)

参考资料

文档中的URLs: