Flutter 中的 async/await 和 Future
含义
在 Flutter/Dart 中,Future
和 async/await
是处理异步操作的核心机制。以下是它们的极简说明:
1. Future
- 是什么:表示一个异步操作的 未来结果(可能未完成)
- 典型场景:网络请求、文件读写、数据库操作等耗时任务
Future<String> fetchData() {return Future.delayed(Duration(seconds: 2), () => "数据加载完成");
}
2. async / await
- 作用:以同步代码风格写异步逻辑,避免回调地狱
- 规则:
async
标记异步函数await
等待 Future 完成并返回实际结果
void loadData() async {String data = await fetchData(); // 等待Future完成print(data); // 输出: "数据加载完成"
}
核心关系
关键词 | 角色 | 示例 |
---|---|---|
Future | 异步任务的"欠条" | Future<int> number |
async | 标记函数内有异步操作 | func() async {...} |
await | 暂停执行直到Future完成 | var x = await future |
注意事项
await
必须在async
函数内使用- 被
await
修饰的代码会顺序执行 - 未处理的异常需要用
try/catch
捕获
比喻理解:
Future
像外卖订单,async/await
是你在家等着外卖送到再开门(而不是反复打电话问到哪了)。
好的!我将基于 async/await
和 Future
的特性,为你编写一个 明确展示异步执行顺序 的示例代码。这个示例会清晰体现:
- 遇到
await
时暂停等待(当前异步任务) - 不相关的代码继续执行(不阻塞主线程)
🎯 示例代码
import 'dart:async';// 示例1: 模拟耗时2秒的网络请求
Future<String> fetchUserData() async {await Future.delayed(Duration(seconds: 2)); // 模拟延迟return "用户数据: 张三";
}// 示例2: 模拟耗时1秒的本地计算
Future<int> calculateScore() async {await Future.delayed(Duration(seconds: 5)); // 模拟延迟return 95;
}void main() async {print("程序开始执行");// 情景1: 需要等待的结果(用await)print("\n--- 开始请求用户数据(需等待结果)---");String userData = await fetchUserData(); // 会阻塞当前async函数内的后续代码print("收到结果: $userData"); // 2秒后执行// 情景2: 不等待的结果(直接执行后续代码)print("\n--- 启动分数计算(不等待)---");Future<int> futureScore = calculateScore(); // 不写await,直接返回Future对象print("此处立即执行,无需等待计算完成");// 打印其他无关操作print("\n--- 其他操作 ---");print("1. 播放背景音乐");print("2. 更新UI界面");// 事后获取分数结果(通过then回调)futureScore.then((score) => print("\n异步计算完成后输出分数: $score"));
}
📊 执行顺序解析
时间线 | 输出内容 | 说明 |
---|---|---|
立即 | 程序开始执行 | main() 同步代码第一步 |
立即 | --- 开始请求用户数据...--- | 进入需要 await 的异步任务 |
2秒后 | 收到结果: 用户数据: 张三 | fetchUserData() 完成,继续执行后续 |
立即 | --- 启动分数计算...--- | 不写 await,直接返回 Future |
立即 | 此处立即执行... | 不阻塞,继续执行 |
立即 | --- 其他操作 --- + 两行输出 | 主线程自由执行其他任务 |
1秒后 | 异步计算完成后输出分数: 95 | calculateScore() 完成后通过 then 触发 |
🔑 关键结论
-
使用
await
:会暂停当前async
函数内的代码执行,直到Future
完成。var result = await someFuture(); // 等待执行完毕
-
不用
await
:立即返回Future
对象,不阻塞后续代码,通过.then()
或后续await
获取结果。someFuture().then((result) { ... }); // 回调模式
-
主线程自由:与当前
async
函数无关的代码(如示例中的播放音乐)始终不受影响。
🌰 现实场景类比
- 点外卖(用 await):你在家等外卖到了才吃饭(阻塞后续动作)。
- 洗衣服(不用 await):启动洗衣机后直接去刷手机(不阻塞),洗完时手机提醒(
.then
)。
总结
如果一个函数返回 Future
,你必须通过以下两种方式之一处理它:
✅ 方式1:await
等待(同步风格)
Future<String> fetchData() async {await Future.delayed(Duration(seconds: 1));return "数据";
}void main() async {String data = await fetchData(); // 等待Future完成print(data); // 输出: "数据"
}
特点:
- 会暂停当前
async
函数,直到Future
完成 - 代码按顺序执行,类似同步代码
✅ 方式2:.then()
回调(异步风格)
void main() {fetchData().then((data) { // 不阻塞,完成后触发回调print(data); // 输出: "数据"});print("这句会先执行"); // 立即执行,不等待Future
}
特点:
- 不阻塞后续代码,
Future
完成后自动触发回调 - 适合不需要立刻结果的场景
❗ 必须二选一的原因
Dart/Flutter 中返回 Future
的函数 本质上是一个异步任务,如果你既不 await
也不 then
:
void main() {fetchData(); // ❌ 错误用法!结果会被丢弃(静默忽略)
}
- 后果:程序不会报错,但你无法获取结果,且无法感知任务是否完成/失败
- 解决方法:通过
await
或then
明确处理
🏆 如何选择?
场景 | 推荐方式 | 例子 |
---|---|---|
需要等待结果再继续 | await | 登录后跳转页面 |
结果可后续处理 | .then() | 上传文件后提示成功 |
并行多个任务 | Future.wait | 同时加载图片和用户数据 |
🔥 终极对比表
特性 | await | .then() |
---|---|---|
代码风格 | 同步顺序 | 回调嵌套 |
是否会阻塞 | 阻塞当前async函数 | 不阻塞 |
异常处理 | 用 try/catch | 用 .catchError() |
适用场景 | 强依赖结果的流程 | 后台任务/通知 |
🌰 简单场景演示
// 组合使用:先await必要数据,再fire-and-forget其他任务
void loadPage() async {// 必须等待用户信息var user = await fetchUser(); print("用户: ${user.name}");// 不等待日志上报uploadLog(user.id).then((_) => print("日志上报成功"));// 继续其他操作print("页面加载完成");
}
总结:
👉 await
= “这个结果我现在就要!”
👉 .then()
= “完成后告诉我,我先忙别的”
记得永远不要让 Future
变成"孤儿"(既不 await
也不 then
)!