Flutter/Dart第04天:Dart异步编程(Future和async/await)
Dart官网代码实验室:https://dart.dev/codelabs/async-await
重要阐明:本博客依据Dart官网代码实验室,但并不是简略的对官网文章进行翻译,我会依据个人研制经历,在掩盖官网文章核心内容情况下,参加自己的一些扩展问题和问题演示和总结,包含称号解说、运用场景阐明、代码样例掩盖、终究完好的场景编程等。
启蒙:过错的异步编程样例
下面是一个过错的异步编程样例,大约进程:经过模仿网络API获取订单ID,然后安排订单ID案牍,终究输出问题。
咱们希望终究输出的是正确的订单ID案牍,可成果并不契合咱们的希望:订单ID并不是T2023092900001,而是Instance of 'Future<String>'
// 1.1 创立订单音讯
String createOrderMessage() {
var order = fetchOrderID();
return '订单ID: $order';
}
// 1.2 获取订单ID内容
Future<String> fetchOrderID() =>
// 假定获取订单ID是一次网络交互,处理进程需求2秒钟,因而模仿了2秒钟回来订单ID
Future.delayed(
const Duration(seconds: 2),
() => 'T2023092900001',
);
void main() {
// 1. 启蒙:过错的异步编程样例
final message = createOrderMessage();
print(message);
// 成果:订单ID: Instance of 'Future<String>'
}
同步编程和异步编程阐明:
- 同步编程:依照代码块次序履行代码块,前面代码块没有履行完结之前,后边代码被堵塞。
- 异步编程:异步操作代码块完结初始化之后,后边代码块就能够履行了(非堵塞),异步代码块履行完结(如上面样例等候2秒钟),履行完结回调代码块(即回调)。
Future异步成果阐明
异步操作的成果都是Future
类的实例(https://api.dart.cn/stable/3.1.3/dart-async/Future-class.html),异步操作有2种状况:未完结和完结状况。调用异步代码块(或函数),回来值都是未完结状况的成果。
- 未完结状况:调用一个异步函数,回来一个
Future<T>
成果,在异步操作履行完毕或许履行犯错之前的状况。 - 完结状况:异步操作履行完毕正常回来成果或许履行犯错,都是完结状况。正常完结的回来成果即
Futrue<T>
的T(如:Future<String>
),假如无需回来成果,则为void,即异步函数的回来值为Future<void>
。假如异步函数履行犯错,则回来成果是一个Error
,能够进行捕获。
下面2个代码样例,分别为回来值为void和犯错成果:
// 2.1 异步操作无回来值
Future<void> fetchOrderID2() {
// 模仿了2秒钟输出了订单ID
return Future.delayed(const Duration(seconds: 2), () => print('ID2:T2023092900002'));
}
// 2.2 反常操作回来过错
Future<void> fetchOrderID3() {
return Future.delayed(const Duration(seconds: 2), () => throw Exception('网络反常'));
}
void main() {
// 2. Future/async/await异步成果阐明
fetchOrderID2();
print('2. fetchOrderID2-Future/async/await异步成果阐明...');
// 成果:
// 2. fetchOrderID2-Future/async/await异步成果阐明...
// ID2:T2023092900002
fetchOrderID3();
print('2. fetchOrderID3-Future/async/await异步成果阐明...');
// 成果:
// 2. fetchOrderID3-Future/async/await异步成果阐明...
// Unhandled exception:
// Exception: 网络反常
}
async/await异步操作界说和运用
async界说一个异步操作,而await则是运用一个异步操作的成果。
在运用async和await是,有2点需求恪守的根本规矩:
- 假如需求界说一个异步函数,则在函数体之前添加async关键字
- 只要在异步函数中(即函数体前有async关键字的函数),await关键字才会收效(也便是await有必要合作async运用)
界说一个异步函数办法样例(即添加async关键字):
// 1. 同步函数转异步函数:无回来成果
// 1.1 同步函数
void funcVoid() {}
// 1.2 异步回来
Future<void> funcVoid() async {}
// 2. 同步函数转异步函数:有回来成果
// 2.1 同步函数
String funcResult() {}
// 2.2 反常函数
Future<String> funcResult() async {}
接下来,咱们来重写第1张中,异步函数代码,以使成果契合咱们预期:
- 获取订单ID函数
fetchOrderID()
前,添加await
关键字。 - 创立订单音讯的函数
createOrderMessageV2()
,添加async
关键字变成异步函数,同回来成果由String
变成Future<String>
异步成果。 - 相同的,
main()
函数调用了异步函数,因而也需求添加async
关键字。
// 3. async/await异步操作界说和运用
Future<String> createOrderMessageV2() async {
var order = await fetchOrderID();
return '订单ID: $order';
}
void main() async {
// 3. async/await异步操作界说和运用
final messageV2 = await createOrderMessageV2();
print('3. async/await异步操作界说和运用');
print('$messageV2');
// 成果:
// 3. async/await异步操作界说和运用
// 订单ID: T2023092900001
}
try/catch异步操作的反常处理
在第2章节中,fetchOrderID3()
异步办法会抛出反常,然后中止程序处理。异步操作的反常,咱们也能够和同步函数调用相同,经过try-catch的方法进行处理。
下面咱们把fetchOrderID3()
运用的当地进行改写,捕获反常然后不中止咱们的程序:
void main() async {
// 4. try/catch异步操作的反常处理
try {
await fetchOrderID3();
print('4. try/catch异步操作的反常处理.');
} catch (e) {
print('4. try/catch异步操作的反常处理: $e');
}
// 成果:4. try/catch异步操作的反常处理: Exception: 网络反常
}
场景编程:异步编程的大合唱
运用场景假定:对当时登录的用户打个招待,一起用户退出登录。由于退出登录操作可被降级,因而退出登录需求捕获一切反常。
- 获取当时登录的用户名,由于是网络API操作,因而是异步操作。
- 退出登录时,需求获取当时缓存的用户名,规划到存储操作,因而也是异步操作。
// 5.1 拼装用户欢迎语
String makeGreeting(String userName) {
return '欢迎你 $userName';
}
// 5.2 获取用户名,异步操作
Future<String> fetchUserName() async {
return Future.delayed(const Duration(seconds: 2), () => 'NTopic.CN');
}
// 5.3 用户登录-打声招待
Future<String> greeting() async {
final userName = await fetchUserName();
return makeGreeting(userName);
}
// 5.4 用户退出-再会
Future<String> goodbye() async {
final userName = await fetchUserName();
return '$userName 下次再会!';
}
void main() async {
// 5. 场景编程:异步编程的大合唱
print('5. 场景编程:异步编程的大合唱...');
print(await greeting());
try {
print(await goodbye());
} catch (e) {
print('5. 场景编程:异步编程的大合唱-Goodbye反常: $e');
}
// 成果:
// 5. 场景编程:异步编程的大合唱...
// 欢迎你 NTopic.CN
// NTopic.CN 下次再会!
}
终究-完好的实例代码
本文介绍的完好的实例代码:
// 第04天:异步编程
// 1.1 创立订单音讯
String createOrderMessage() {
var order = fetchOrderID();
return '订单ID: $order';
}
// 1.2 获取订单ID内容
Future<String> fetchOrderID() =>
// 假定获取订单ID是一次网络交互,处理进程需求2秒钟,因而模仿了2秒钟回来订单ID
Future.delayed(
const Duration(seconds: 2),
() => 'T2023092900001',
);
// 2.1 异步操作无回来值
Future<void> fetchOrderID2() {
// 模仿了2秒钟输出了订单ID
return Future.delayed(const Duration(seconds: 2), () => print('ID2:T2023092900002'));
}
// 2.2 反常操作回来过错
Future<void> fetchOrderID3() {
return Future.delayed(const Duration(seconds: 2), () => throw Exception('网络反常'));
}
// 3. async/await异步操作界说和运用
Future<String> createOrderMessageV2() async {
var order = await fetchOrderID();
return '订单ID: $order';
}
// 5.1 拼装用户欢迎语
String makeGreeting(String userName) {
return '欢迎你 $userName';
}
// 5.2 获取用户名,异步操作
Future<String> fetchUserName() async {
return Future.delayed(const Duration(seconds: 2), () => 'NTopic.CN');
}
// 5.3 用户登录-打声招待
Future<String> greeting() async {
final userName = await fetchUserName();
return makeGreeting(userName);
}
// 5.4 用户退出-再会
Future<String> goodbye() async {
final userName = await fetchUserName();
return '$userName 下次再会!';
}
void main() async {
// 1. 启蒙:过错的异步编程样例
final message = createOrderMessage();
print(message);
// 2. Future/async/await异步成果阐明
fetchOrderID2();
print('2. fetchOrderID2-Future/async/await异步成果阐明...');
// fetchOrderID3();
print('2. fetchOrderID3-Future/async/await异步成果阐明...');
// 3. async/await异步操作界说和运用
final messageV2 = await createOrderMessageV2();
print('3. async/await异步操作界说和运用');
print('$messageV2');
// 4. try/catch异步操作的反常处理
try {
await fetchOrderID3();
print('4. try/catch异步操作的反常处理.');
} catch (e) {
print('4. try/catch异步操作的反常处理: $e');
}
// 5. 场景编程:异步编程的大合唱
print('5. 场景编程:异步编程的大合唱...');
print(await greeting());
try {
print(await goodbye());
} catch (e) {
print('5. 场景编程:异步编程的大合唱-Goodbye反常: $e');
}
}
我的本博客原地址:https://ntopic.cn/p/2023092901