模式切换
异步编程
Future 的基本概念与使用
Future 的概念
Future
表示一个异步计算的结果,与 JavaScript 中的 Promise
类似。用于处理异步操作,异步处理成功就执行成功的操作,异步处理失败就执行失败的操作。
一个 Future
对象只会对应一个结果,要么成功,要么失败。Future
的所有 API 返回值类型都是 Future
。
Future.then
then
方法用于注册成功回调。
示例:
dart
void main() {
Future(() => 42).then((value) {
print('Result: $value');
});
}
其中,then 方法还可以接收一个可选的 onError 参数,用于注册失败回调。
示例:
dart
void main() {
Future.error('Error occurred').then((value) {
print('Result: $value');
}, onError: (error) {
print('Error: $error');
});
}
Future.catchError
catchError
方法用于注册失败回调。
示例:
dart
void main() {
Future(() => 42).then((value) {
print('Result: $value');
}).catchError((error) {
print('Error: $error');
});
}
在上方代码中,当 Future 执行失败时,会调用 catchError 方法注册的回调函数,不会调用 then 方法注册的回调函数。
Future.whenComplete
whenComplete
方法用于注册无论成功或失败都会执行的回调。例如在关闭文件、释放资源、关闭加载动画等场景。
示例:
dart
void main() {
Future(() => 42).then((value) {
print('Result: $value');
}).catchError((error) {
print('Error: $error');
}).whenComplete(() {
print('Done');
});
}
Future.wait
wait
方法用于等待多个 Future 完成,接收一个 Future 数组,当所有 Future 都完成时返回一个 Future,如果其中一个 Future 失败,则触发失败的回调。
示例:
dart
void main() {
var future1 = Future.delayed(Duration(seconds: 2), () => 1);
var future2 = Future.delayed(Duration(seconds: 1), () => 2);
Future.wait([future1, future2]).then((value) {
print('Result: $value');
}).catchError((error) {
print('Error: $error');
});
}
async 和 await
Dart 使用 async
和 await
简化异步编程,使异步任务串行化、代码更加清晰易读。
使用 async
声明异步函数,使用 await
等待异步结果。
无论是在 Dart 或是 JavaScript 中,async
和 await
都只是语法糖,本质上编译器/解释器会将其转换为 Future
或 Promise
。
例如在下面的场景中,用户先登录,登录成功后根据用户 ID 获取用户信息,最后将用户信息存储到本地。
dart
// 登录
Future<void> login() async {
await Future.delayed(Duration(seconds: 1));
print('Login success');
}
// 获取用户信息
Future<String> getUserInfo(int userId) async {
await Future.delayed(Duration(seconds: 1));
return 'User: $userId';
}
// 保存用户信息
Future<void> saveUserInfo(String userInfo) async {
await Future.delayed(Duration(seconds: 1));
print('Save user info: $userInfo');
}
在没有引入 async
和 await
的情况下,会出现回调地狱(层层嵌套)的情况。代码如下:
dart
void main() {
login().then((_) {
getUserInfo(1).then((userInfo) {
saveUserInfo(userInfo).then((_) {
print('All done');
});
});
});
}
为了解决回调地狱的问题,可以使用下面两种方式:
- 使用 then 方法
dart
void main() {
login().then((_) {
return getUserInfo(1);
}).then((userInfo) {
return saveUserInfo(userInfo);
}).then((_) {
print('All done');
});
}
- 使用 async 和 await
dart
void main() async {
try {
await login();
var userInfo = await getUserInfo(1);
await saveUserInfo(userInfo);
print('All done');
} catch (e) {
print('Error: $e');
}
}
Stream 的概念与使用
Stream 的概念
Stream
是一种表示异步数据序列的抽象,允许处理一系列异步事件,例如从文件读取数据、处理网络响应或者监听用户输入等。Stream
提供了一种简洁而强大的方式来处理这些异步数据流。
Stream
有三个基本概念:
- 数据源:Stream 从数据源获取数据。数据源可以是文件、网络、用户输入等。
- 监听器(Listener):你可以添加监听器到 Stream 上,以便在数据到达时处理数据。
- 事件:Stream 可以发出三种类型的事件,数据(data)、错误(error)和结束(done)。
监听 Stream
Dart 提供了一些基本的 Stream 类,比如 StreamController
,可以用来创建自定义的 Stream。
dart
import 'dart:async';
void main() async {
// 创建一个 StreamController
StreamController<int> controller = StreamController<int>();
// 监听 Stream
controller.stream.listen(
(data) {
print('Received data: $data');
},
onError: (error) {
print('Error: $error');
},
onDone: () {
print('Stream is done.');
},
cancelOnError: true,
);
// 添加数据到 Stream
controller.add(1);
controller.add(2);
controller.add(3);
// 关闭 Stream
controller.close();
}
转换 Stream
Dart 提供了许多 StreamTransformer
类,允许你对 Stream 进行各种变换操作,比如映射(map)、过滤(filter)和聚合(reduce)等。
dart
import 'dart:async';
void main() async {
// 创建一个简单的 Stream
Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);
// 使用 map 变换 Stream
stream
.map((data) => data * 2)
.listen(
(data) {
print('Mapped data: $data');
},
);
}
处理 Stream 错误
通过 onError
回调来处理 Stream 中的错误。
dart
import 'dart:async';
void main() async {
// 创建一个带有错误的 Stream
Stream<int> stream = Stream.fromIterable([1, 2, 3])
.concat(Stream.error(Exception('An error occurred')));
stream.listen(
(data) {
print('Received data: $data');
},
onError: (error) {
print('Error: $error');
},
);
}
常见的 Stream 类型
BroadcastStream
:可以有多个监听器的 Stream。SingleSubscriptionStream
:只能有一个监听器的 Stream。EventSink
和EventStream
:用于实现自定义的 Stream 控制器和 Stream。
高级用法
- 使用
async*
创建自定义 Stream
使用 async*
语法来创建自定义的 Stream。
dart
import 'dart:async';
Stream<int> customStream() async* {
for (int i = 0; i < 5; i++) {
await Future.delayed(Duration(seconds: 1)); // 模拟异步操作
yield i;
}
}
void main() async {
customStream().listen(
(data) {
print('Received data: $data');
},
);
}
- 结合 Future 使用 Stream
Stream 可以和 Future 结合使用,以便在异步操作完成后继续处理数据。
dart
import 'dart:async';
void main() async {
Future<int> fetchData() async {
await Future.delayed(Duration(seconds: 1)); // 模拟异步操作
return 42;
}
Stream<int> stream = Stream.fromFuture(fetchData());
stream.listen(
(data) {
print('Received data: $data');
},
);
}
异步生成器(yield 和 yield*)
yield
使用 yield
逐步生成数据。
示例:
dart
Stream<int> countStream() async* {
for (int i = 1; i <= 3; i++) {
yield i;
}
}
void main() async {
await for (var value in countStream()) {
print('Value: $value');
}
}
yield*
使用 yield*
转发另一个生成器。
示例:
dart
Stream<int> countStream() async* {
yield* Stream.fromIterable([1, 2, 3]);
}
void main() async {
await for (var value in countStream()) {
print('Value: $value');
}
}