本代码是学习Future
和async
await
关键字编写异步代码。使用嵌入式DartPad编辑器,您可以通过运行示例代码并完成练习来测试您的知识。
本文主要包含:
- 如何以及何时使用
async
await
关键字。
异步代码的重要性
异步操作使您的程序可以在等待另一个操作完成的同时完成工作。以下是一些常见的异步操作:
- 通过网络获取数据。
- 写入数据库。
- 从文件读取数据
要在Dart中执行异步操作,可以使用Future
类和async
和await
关键字。
示例:错误地使用异步函数
以下示例显示了使用异步函数(fetchUserOrder()
)的错误方法。稍后,您将使用async和修复示例await。在运行此示例之前,请尝试找出问题所在–您认为输出将是什么?
// This example shows how *not* to write asynchronous Dart code.
String createOrderMessage() {
var order = fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is more complex and slow.
Future.delayed(
Duration(seconds: 2),
() => 'Large Latte',
);
void main() {
print(createOrderMessage());
//Your order is: Instance of '_Future<String>'
}
这就是示例无法打印fetchUserOrder()最终产生的值的原因:
-
fetchUserOrder()
是一个异步函数,在延迟后,它提供了一个描述用户顺序的字符串:'Large Latte'
, - 要获取用户的订单,
createOrderMessage()
应调用fetchUserOrder()
并等待其完成。因为createOrderMessage()
它没有等待fetchUserOrder()
到结束,createOrderMessage(
)没有得到字符串值fetchUserOrder()
,最终提供的结果。 - 相反,
createOrderMessage()
它代表待完成的工作:未完成的future。 - 由于
createOrderMessage()
无法获取描述用户订单的值,因此该示例无法在控制台上打印“ Large Latte”,而是打印“您的订单是:'_ Future的实例'”。
在接下来的部分中,我们将了解Future以及如何使用Future(使用async和await),以便能够将必要的代码编写fetchUserOrder() 为在控制台上打印所需的值('Large Latte')。
关键词:
- 同步操作:同步操作会阻止其他操作执行到完成。
- 同步功能:同步功能仅执行同步操作。
- 异步操作:异步操作一旦启动,就可以在完成之前执行其他操作。
- 异步函数:异步函数至少执行一个异步操作,也可以执行同步操作。
Fulure是什么?
Fulure表示异步操作的结果,并且可以具有两种状态:未完成或已完成
未完成
当您调用异步函数时,它将返回一个未完成的Fulure。Fulure正在等待函数的异步操作完成或引发错误。
已完成
如果异步操作成功,则Fulure将以一个值完成。否则,它会以错误完成。
Future值
Future是一个Future<T>
所以,我们可以将任何值作为返回类型
完成错误
如果该函数执行的异步操作由于任何原因而失败,则将来会出现错误。
示例:介绍Fulure
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info from another service or database.
return Future.delayed(Duration(seconds: 2), () => print('Large Latte'));
}
void main() {
fetchUserOrder();
print('Fetching user order...');
//Fetching user order...
//Large Latte
}
在以下示例中,fetchUserOrder()
返回打印到控制台后完成的Fulure。因为它不返回可用的值,所以 fetchUserOrder()
的类型Future<void>
。在运行示例之前,请尝试预测将首先打印的内容:“'Large Latte'
”或“Fetching user order...
”。
示例:错误完成
运行以下示例以查看将来如何完成并出现错误。稍后,您将学习如何处理该错误。
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info but encounters a bug
return Future.delayed(Duration(seconds: 2),
() => throw Exception('Logout failed: user ID is invalid'));
}
void main() {
fetchUserOrder();
print('Fetching user order...');
//Fetching user order...
//Uncaught Error: Exception: Logout failed: user ID is invalid
}
在此示例中,fetchUserOrder()
显示一个错误,指示用户ID无效。
这个错误的演示是为了理解学习如何使用async和await关键字获得结果
快速总结:
Future<T>
实例产生类型的值T如果Future未产生可用价值,则Future的类型为
Future<void>
。Future可能处于以下两种状态之一:未完成或已完成。
当您调用返回未来的函数时,该函数会将要完成的工作排队,并返回未完成的未来。
当future的操作完成时,future以一个值或一个错误完成。
关键词:
- Future:Dart Future类。
- future:Dart Future类的实例。
使用Future:async和await
在async和await关键字提供一个声明的方式来定义异步函数,并使用其结果。使用async和时请记住以下两个基本准则await:
- **要定义异步函数,要在函数主体之前添加:async **
- 该await关键字只能在async函数中使用
main()
从同步功能转换为异步功能的示例。
void main() async { ··· }
如果函数具有声明的返回类型,则将类型更新为Future<T>
,其中T是函数返回的值的类型。如果该函数未明确返回值,则返回类型为 Future<void>
:
Future<void> main() async { ··· }
现在您有了async函数,可以使用await关键字等待将来完成:
print(await createOrderMessage());
如以下两个示例所示,asyncand await关键字生成的异步代码看起来与同步代码非常相似。异步示例中突出显示了唯一的区别,
- 同步
String createOrderMessage() {
var order = fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is
// more complex and slow.
Future.delayed(
Duration(seconds: 2),
() => 'Large Latte',
);
void main() {
print('Fetching user order...');
print(createOrderMessage());
// Fetching user order...
// Your order is: Instance of _Future<String>
}
- 异步
Future<String> createOrderMessage() async {
var order = await fetchUserOrder();
return 'Your order is: $order';
// Fetching user order...
// Your order is: Large Latte
}
Future<String> fetchUserOrder() =>
// Imagine that this function is
// more complex and slow.
Future.delayed(
Duration(seconds: 2),
() => 'Large Latte',
);
Future<void> main() async {
print('Fetching user order...');
print(await createOrderMessage());
}
异步示例在三种方面有所不同:
- 的返回类型
createOrderMessage()
从变化String到Future<String>
。 - 该async关键字的函数体之前出现
createOrderMessage()
和main()
。 - 该await关键字调用异步函数之前出现
fetchUserOrder()
和createOrderMessage()
。
关键词:
- async:您可以async在函数主体之前使用关键字将其标记为异步。
- 异步函数:async函数是带有async 关键字的函数。
- await:您可以使用await关键字来获取异步表达式的完整结果。该await关键字只有内工作的async功能。
具有async和await的执行流
一个async函数同步运行直到第一个 await关键字。这意味着在async函数体内,第一个await关键字之前的所有同步代码将立即执行。
示例:异步函数中的执行
Future<void> printOrderMessage() async {
print('Awaiting user order...');
var order = await fetchUserOrder();
print('Your order is: $order');
}
Future<String> fetchUserOrder() {
// Imagine that this function is more complex and slow.
return Future.delayed(Duration(seconds: 4), () => 'Large Latte');
}
Future<void> main() async {
countSeconds(4);
await printOrderMessage();
}
// You can ignore this function - it's here to visualize delay time in this example.
void countSeconds(int s) {
for (var i = 1; i <= s; i++) {
Future.delayed(Duration(seconds: i), () => print(i));
}
}