Dart Completer (任务完成器) 详解
Dart Completer (任务完成器) 详解
1. 什么是 Completer?
Completer 是 Dart 中用于手动创建和管理 Future 的工具。
- 普通 Future:由
async函数自动管理,一旦开始执行便无法在外部手动干预其完成时机。 - Completer:提供了一个“手动挡”的
Future。它允许你创建一个Future,并把“何时完成”以及“以什么结果完成”的控制权掌握在自己手中。
简单来说,当你需要返回一个 Future 给调用者,但这个 Future 的结果需要在稍后的某个时刻(例如回调函数触发时)才能确定,这时就是使用 Completer 的最佳时机。
2. 核心结构
Completer 主要由两个核心成员组成:
completer.future- 作用:这是暴露给外部等待的对象。
- 行为:调用者
await这个属性时,程序会暂停,直到你手动调用complete方法。
completer.complete(value)- 作用:这是“触发完成”的开关。
- 行为:一旦调用,所有正在等待
future的代码会立即收到结果并继续执行。
3. 生活中的类比:取餐器
想象你在快餐店点餐的过程:
- 创建 Completer:你点完餐,服务员给了你一个 **取餐器 (Completer)**。
- await future:你拿着取餐器找座位坐下,看着取餐器 **等待 (await)**。
- 异步操作:后厨正在 **制作汉堡 (异步任务)**。
- 调用 complete:汉堡做好了,服务员按下柜台上的发射器 **(completer.complete())**。
- 完成:你手中的取餐器响了,你起身去取餐。
4. 基本用法示例
1 | import 'dart:async'; |
执行顺序:
1. 主程序开始2. 启动异步任务...3. 等待结果...- (等待3秒)
4. 任务完成,手动调用 complete5. 收到结果: 任务成功数据
5. 常见应用场景
场景一:将回调 (Callback) 转换为 Future
这是 Completer 最经典的应用场景。很多老旧的库或底层 API 仍然使用回调函数风格,我们可以用 Completer 将其包装成现代的 async/await 风格。
旧式 API (Callback 风格):
1 | void oldDownload(String url, Function(String) onSuccess, Function(String) onError) { |
使用 Completer 包装 (Future 风格):
1 | Future<String> downloadAsync(String url) { |
场景二:解决并发请求合并 (Request Deduplication)
这正是我们在 CleanupManager 中解决的问题。当多个页面同时请求同一个耗时资源时,我们不希望发起多次重复请求,而是希望后来的请求“搭便车”。
实现模式:
1 | class DataManager { |
效果:
- 调用 A 进来 -> 创建
Completer-> 开始请求。 - 调用 B 进来 -> 发现
Completer存在 ->await它。 - 调用 C 进来 -> 发现
Completer存在 ->await它。 - 请求结束 -> 调用
complete()-> A, B, C 同时收到通知并继续执行。
6. 总结
| 特性 | 普通 Future | Completer |
|---|---|---|
| 创建方式 | async 函数自动返回 |
Completer() 构造函数 |
| 完成控制 | 函数 return 时自动完成 | 开发者手动调用 complete() |
| 适用场景 | 大多数标准异步逻辑 | 桥接回调 API、并发控制、自定义异步流程 |
掌握 Completer,意味着你从“只会使用异步”进阶到了“能够设计和控制异步流程”的水平。