Flutter 异步与同步(1):异步与同步机制(async、await 和 Future)
在 Flutter/Dart 中,async 和 await 是处理异步编程的核心关键字,它们可以让你以同步的方式编写异步代码,显著提高代码的可读性和可维护性。
一、同步/异步的理解
await:同步机制
同步操作会阻止其他操作执行,直到完成为止。同步就好比打电话一样,打电话时都是一个人在说另一个人听,一个人在说的时候另一个人等待,等另一个人说完后再接着说。

async:异步机制
异步操作一旦启动,就允许其他操作在其完成之前执行。异步就好比发邮件一样,收件人和发件人都不需要相互等待,发件人写完邮件的时候简单的点个发送就可以了,收件人收到后就可以阅读啦,收件人和发件人不需要相互依赖、不需要相互等待。

二、Dart 的异步模型
Flutter 的 UI 渲染依赖于 主线程(UI 线程) ,如果任务执行时间过长,会导致界面卡顿(掉帧)。为了保证流畅性,Flutter 采用 异步模型 处理耗时任务,比如:
- 网络请求
- 文件读写
- 数据库操作
- 动画
- I/O 操作
Dart 的单线程模型
Dart 采用 单线程事件循环,与 JavaScript 类似:
- 事件按照 先进先出(FIFO) 执行
- 任务分为:
- 微任务(Microtask) :优先执行(类似 JS 的
Promise.then) - 事件任务(Event Task) :比如 I/O、鼠标点击、定时器等
- 微任务(Microtask) :优先执行(类似 JS 的
三、Future 的基本概念
(1)核心关键字
- async: 标记函数为异步函数
- await: 等待异步操作完成
- Future: 表示可能在未来完成的操作
(2)基本语法
Future<void> fetchData() async {
// 同步代码
print('开始获取数据');
// 异步操作
var data = await http.get('https://api.example.com/data');
// 等待完成后执行
print('获取到数据: $data');
}
(3)引入 async/await 的原因
在 Dart 中,Future 代表 一个异步操作的结果:
Future<String> fetchData() {
return Future.delayed(Duration(seconds: 2), () => "数据加载完成");
}
需要使用 .then() 处理,获取 fetchData 这个异步操作的结果数据,然后打印该数据:
fetchData().then((data) {
print(data);
});
但 .then() 方式 嵌套太多,会变得难以阅读(回调地狱):
fetchData().then((data) {
process(data).then((result) {
save(result).then((_) {
print("完成");
});
});
});
为了解决这个问题,Dart 引入了 async/await。
四、async/await 的工作原理
async 和 await 关键字构成了异步编程的基础,它们极大地简化了异步操作的处理流程。async 关键字用于声明一个函数为异步函数,这意味着该函数的执行可能不会立即完成,并且会返回一个 Future 对象。
-
Future 是 Dart 中的一个核心类,代表一个可能在未来某个时间点返回结果的计算。当在 async 函数内部遇到 await 关键字时,执行流程会暂停,直到 await 后面的异步操作完成。这种暂停并不会阻塞整个线程,而是允许 Dart 的事件循环继续处理其他事件,如用户交互或动画,从而保持应用的响应性。
-
使用 await 的优势在于它能够让异步代码的逻辑流程更加直观和清晰。开发者不再需要通过嵌套回调(俗称“回调地狱”)来处理异步操作的结果,而是可以以近似同步的方式编写代码,使得逻辑更容易理解和维护。
-
async 和 await 在错误处理方面也提供了便利。在 async 函数中,可以使用传统的 try-catch 结构来捕获异步操作中抛出的异常,这比处理 Future 的 catchError 方法更加直观。
使用 async/await 让代码更直观
Future<String> fetchData() {
return Future.delayed(Duration(seconds: 2), () => "数据加载完成");
}
Future<void> loadData() async {
String data = await fetchData(); // 等待 await 后面的 fetchData 这个异步操作执行完,再获取结果数据
print(data);
}
等价于:
fetchData().then((data) {
print(data);
});
async/await 只是 Future 的语法糖,它不会改变 Future 本身的行为,而是让异步代码像同步代码一样编写。
五、事件循环(Event Loop)与任务调度
Flutter 运行时采用 事件循环(Event Loop) 处理异步任务:
- 同步任务 立即执行
- 微任务(Microtask) 在当前事件循环执行完毕后立即执行
- 事件任务(Event Task) 交给事件队列,等待空闲时执行
Dart 采用 单线程事件循环 处理所有任务,执行顺序:
- 先执行 同步任务
- 再执行 所有微任务 (特点有:优先级高,比事件任务先执行;一次性执行完所有微任务;不能主动终止;适用于 短小的任务 任务调度(State 更新)(日志收集)(UI 细节调整))
- 最后执行 一个事件任务(特点有:事件任务 适用于 IO、定时器、用户交互等任务,优先级低于微任务,如用户输入(点击、键盘事件))
- 然后继续执行微任务(如果有)
示例:
void main() {
print("1");
Future(() => print("2"));
scheduleMicrotask(() => print("3"));
print("4");
}
执行顺序:
print("1")print("4")(同步任务执行完毕)print("3")(微任务队列执行)print("2")(事件任务执行)
六、await 背后的状态机
await 并不会阻塞线程,而是将代码拆分为多个 Future 回调,然后利用 状态机 进行调度。
示例
Future<void> main() async {
print("A");
await Future.delayed(Duration(seconds: 1));
print("B");
}
等价代码
Future<void> main() {
print("A");
return Future.delayed(Duration(seconds: 1)).then((_) {
print("B");
});
}
执行过程
print("A")Future.delayed被加入 事件队列- 主线程任务执行完毕,事件循环开始处理
Future print("B")
await 关键字 会拆分成多个 Future 回调,每个 await 相当于创建了一个新的 Future.then。
七、async/await 源码解析
在 Dart 源码中,async 代码会被编译成 Future 回调链,并使用 状态机 控制执行。
查看 dart:async 中的 Future 代码:
Future<T> async<T>(FutureOr<T> Function() computation) {
return Future<T>(() {
return computation();
});
}
Dart 运行时会自动将 async 方法转换成 Future 状态机。
示例
Future<int> compute() async {
int result = await Future.value(10);
return result;
}
实际执行时,相当于:
Future<int> compute() {
return Future.value(10).then((result) {
return result;
});
}
Dart 运行时 通过状态机调度 await 关键字,使其执行时不会阻塞主线程。
八、async/await 使用
(1)声明异步函数
任何返回 Future 的函数都应该标记为 async:
Future<String> getUserName() async {
// ...
}
(2)等待单个 Future
Future<int> getAge() async {
await Future.delayed(Duration(seconds: 1)); // 模拟延迟
return 25;
}
void printAge() async {
int age = await getAge();
print('年龄: $age');
}
(3)处理多个 Future
并行执行
Future<void> fetchAllData() async {
// 同时启动所有异步操作
Future<String> userFuture = getUser();
Future<String> postsFuture = getPosts();
Future<String> commentsFuture = getComments();
// 等待所有完成
final results = await Future.wait([userFuture, postsFuture, commentsFuture]);
print('用户: ${results[0]}');
print('帖子: ${results[1]}');
print('评论: ${results[2]}');
}
顺序执行
Future<void> fetchSequentially() async {
final user = await getUser();
final posts = await getPosts(user.id);
final comments = await getComments(posts.first.id);
print('完整数据链: $user -> $posts -> $comments');
}
(4)处理异常
使用 try-catch 捕获 async/await 异常:
// 示例1
Future<void> fetchData() async {
try {
String data = await Future.error("网络异常");
print(data);
} catch (e) {
print("捕获异常: $e");
}
}
// 示例2
Future<void> loadData() async {
try {
var data = await fetchData();
print('数据加载成功: $data');
} catch (e) {
print('发生错误: $e');
} finally {
print('加载操作完成');
}
}
避免未处理的异常导致应用崩溃。
九、Flutter 中的实际应用
(1)网络请求
Future<List<Post>> fetchPosts() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
return (jsonDecode(response.body) as List)
.map((post) => Post.fromJson(post))
.toList();
} else {
throw Exception('加载失败');
}
}
(2)文件操作
Future<void> saveFile(String content) async {
final file = File('document.txt');
await file.writeAsString(content);
print('文件保存成功');
}
(3)数据库访问
Future<List<User>> getUsers() async {
final db = await DatabaseHelper.instance.database;
final maps = await db.query('users');
return maps.map((map) => User.fromMap(map)).toList();
}
(4)结合 setState 使用
Future<void> loadAndRefresh() async {
setState(() => isLoading = true);
try {
data = await fetchData();
} catch (e) {
errorMessage = e.toString();
} finally {
setState(() => isLoading = false);
}
}
十、常见问题解决方案
(1)避免 await 阻塞 UI
问题代码:
void main() async {
await Future.delayed(Duration(seconds: 3)); // UI 会卡顿
runApp(MyApp());
}
改进方案:
void main() {
runApp(MyApp());
Future.delayed(Duration(seconds: 3), () {
print("初始化完成");
});
}
(2)避免嵌套地狱
问题代码:
Future<void> nestedHell() async {
await func1().then((r1) async {
await func2(r1).then((r2) async {
await func3(r2).then((r3) {
print(r3);
});
});
});
}
改进方案:
Future<void> cleanCode() async {
final r1 = await func1();
final r2 = await func2(r1);
final r3 = await func3(r2);
print(r3);
}
(3)正确处理 async/await 与 then 混用
// 不推荐
Future<void> badPractice() async {
await future.then((value) => process(value));
}
// 推荐
Future<void> goodPractice() async {
final value = await future;
process(value);
}
(4)避免不必要的 async
// 不必要
Future<int> unnecessaryAsync() async {
return 42;
}
// 改进
Future<int> betterVersion() {
return Future.value(42);
}
九、结论
async/await只是Future的语法糖,本质是 状态机 +Future.then()await不会阻塞 UI 线程- Dart 采用 事件循环 处理异步任务
- 微任务(Microtask)优先于事件任务(Event Task)
- 优化:并行
await,避免 UI 阻塞
理解 async/await 的底层原理,有助于编写更高效、可维护的 Flutter 代码
参考:
Flutter中同步与异步_flutter async-CSDN博客
详细解释Flutter中 async/await 的工作原理在 Flutter(Dart)中,async/await 是 - 掘金

浙公网安备 33010602011771号