名称: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()方法不会运行,状态保持不变。
默认情况下,检查基于动作的运行时类型——同一动作类的多个实例不能同时运行。
常见用例
- 防止重复表单提交 - 阻止用户意外多次提交表单
- 保护API调用 - 确保保存/更新/删除操作不会并发执行
- 资源密集型任务 - 防止昂贵的计算并行运行
- 避免竞态条件 - 确保必须不重叠的操作顺序执行
自定义
允许不同参数并发运行
重写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不能与以下混入组合:
ThrottleUnlimitedRetryCheckInternet- 大多数乐观更新混入(检查兼容性矩阵)
参考资料
文档中的URLs:
- https://asyncredux.com/sitemap.xml
- https://asyncredux.com/flutter/advanced-actions/control-mixins
- https://asyncredux.com/flutter/advanced-actions/action-mixins
- https://asyncredux.com/flutter/advanced-actions/aborting-the-dispatch
- https://asyncredux.com/flutter/basics/dispatching-actions
- https://asyncredux.com/flutter/basics/async-actions