异步编程:使用 Future 和 async-await | Dart
什么是异步操作/异步操作的作用?
Dart 代码运行在单个执行"线程"中。如果 Dart 代码在执行时阻塞,例如:处理一个需要长时间运行的计算操作或等待 I/O 完成。此时整个程序会被"冻结"。
异步操作可以让你的程序在等待一个操作完成时继续处理其它的工作。Dart 使用 Future
对象来表示异步操作的结果。异步计算不会阻塞所有计算直到结果可用,而是立即返回一个 Future
,最终将"完成"结果
future是什么?
future 是 Future<T> 类的对象,其表示一个 T
类型的异步操作结果。如果异步操作不需要结果,则 future 的类型可为 Future<void>
。当一个返回 future 对象的函数被调用时,会发生两件事:
-
将函数操作列入队列等待执行并返回一个未完成的
Future
对象。 -
不久后当函数操作执行完成,
Future
对象变为完成并携带一个值或一个错误。
如何使用future?
使用关键字 async
和 await
async
和 await的作用?
它们允许你不使用 Future
的 API (Future.then和Future.catchError)编写看起来与同步代码一样的异步代码。
-
在异步函数中使用
await
关键字暂停代码的执行,直到对应的 future 完成。 -
可以使用 try-catch 表达式来捕获异步函数中代码的执行错误。
case1:
/// 新建的Future学习类
class FutureStudy{
// 延时1秒钟
Future<void> futureDelay() async {
await Future.delayed(new Duration(seconds: 1),() =>print("1秒后打印-延时任务"));
}
}
main() async {
// 调用 FutureStudy 中的延时方法 -延时在前 正常在后
FutureStudy().futureDelay();
print("正常打印");
}
打印结果:延时语句在前但是却后打印,这是因为:
await Future.delayed(new Duration(seconds: 1),() =>print("1秒后打印-延时任务")); 会阻塞一秒钟
而异步操作可以让你的程序在等待一个操作完成时继续处理其它的工作
I/flutter ( 3898): 正常打印
I/flutter ( 3898): 1秒后打印-延时任务
case2:
main() async {
// 调用 FutureStudy 中的延时方法 -延时在前 正常在后
await FutureStudy().futureDelay();
print("正常打印");
}
I/flutter ( 3898): 1秒后打印-延时任务
I/flutter ( 3898): 正常打印
此时先打印延时方法里的是因为:
main中 await FutureStudy().futureDelay()需要先等待futureDelay()内部方法完成后再执行后面的语句,所以体现的是一个同时操作的效果。
case3:
在此基础上修改 FutureStudy 中的代码
class FutureStudy{
futureDelay() async {
// 模拟延时效果 - 等待两秒后再执行
Future.delayed(const Duration(seconds: 1),() =>print("1秒后打印-延时任务"));
}
}
I/flutter ( 3898): 正常打印
I/flutter ( 3898): 1秒后打印-延时任务
此时的打印结果和case1相同,这是因为main中 await FutureStudy().futureDelay() 要等待函数执行完成后再执行其他语句,但是函数内部遵循的是异步操作,此时它可以执行其他语句。
使用 Future
API
由于Future可以通过两种方式完成,要么使用值(如果异步计算成功),要么使用错误(如果计算失败),因此可以为其中一种或两种情况安装回调。
Future的所有API的返回值仍然是一个Future对象,Future.then可以使用这个future。
Future<R> then<R>(FutureOr<R> onValue(T value), {Function? onError});
then()会在 Future函数体执行完毕后立刻执行
如果,future是作为值返回的,则调用回调函数 onValue 回调函数,里面的参数是value去future返回的值,如果future的结果是错误则调用 onError 回调函数
then中的回调onError和Future.catchError
Future.catchError回调只处理原始Future抛出的错误,不能处理回调函数抛出的错误,onError只能处理当前Future的错误
Future.whenComplete
Future.whenComplete 在Future完成之后总是会调用,不管是错误导致的完成还是正常执行完毕
Future.wait
等待多个Future完成,并收集它们的结果。有两种情况
- 所有Future都有正常结果返回。则Future的返回结果是所有指定Future的结果的集合
- 其中一个或者几个Future发生错误,产生了error。则Future的返回结果是第一个发生错误的Future的值
Future.foreach
根据某个集合对象,创建一系列的Future。并且会按顺序执行这些Future
void testFuture() async {
Future.forEach({1,2,3}, (num){
return Future.delayed(Duration(seconds: num),(){print("第$num秒执行");});
});
}
testFuture();
print("在testFuture()执行之后打印。");