前言
什么是Future呢?我看到的第一反应想到的就是翻译——未来,但未来啥呢,没有一个准确的答案。后来通过了解明白Future它表示一个可能还未完成的异步操作的结果,我联系了一下,这不是和未来一个意思吗?我是这样理解的,Dart单线程实现异步操作是通过事件循环机制将异步I/O操作委托给操作系统底层完成,这意味着当前并不知道这个异步操作的结果,需要等待操作系统通知,那这不就是未来的结果吗。是不是感觉很神奇?那下面我们就一起去看看Dart中关于Future的细节吧。
一、Future定义
Future表示一个可能还未完成的异步操作的结果。是不是感觉一脸懵?这可能是我们还没有真正理解异步操作。下面我们以一个生活中的例子来快速回顾一下异步操作。
例子:异步操作就像我们订外卖时骑手送餐这个过程。我们(主线程)不用因为订了外卖(耗时的操作如网络请求)就一直站在门口等待着送达,而是在等待过程中去做其他的事(执行下一个操作),当外卖送达后骑手会通知我们取结果(Future)。
二、Future的创建
Future的创建就是通过编写代码实现异步操作的过程。通过六大工厂构造函数或异步函数async创建,下面我们逐步介绍。
2.1、Future()
Future(FutureOr<T> computation())需要传入一个返回类型为FutureOr<T>的函数。
FutureOr<T>:表示泛型类型的同步结果或泛型类型的异步结果。- computation():函数内为用代码实现的异步操作过程。其返回类型为
FutureOr<T>意味着可以根据逻辑返回同步结果或异步结果。
下面是Future创建的核心代码。
factory Future(FutureOr<T> computation()) {
// 1、创建一个未完成的_Future 实例 result。
_Future<T> result = new _Future<T>();
// 2、调度异步执行
Timer.run(() { // 将computation加入事件队列。
FutureOr<T> computationResult; // 声明FutureOr<T>类型的变量。
try {
// 3、执行传入的异步操作的代码
computationResult = computation();
} catch (e, s) {
// 4、执行过程中出现错误的处理。将错误信息传递给_Future实例
_completeWithErrorCallback(result, e, s);
return;
}
// 5、结果处理。
result._complete(computationResult);
});
// 6、返回异步操作执行的结果
return result;
}
示例: 返回一个同步值。
FutureOr<int> buildComputation() {
int age = 10;
return age;
}
void main() {
Future(buildComputation);
}
2.2、Future.delayed()
创建指定延迟时间执行的异步任务。必须传入指定的延迟时间duration。
参数:Duration duration, [FutureOr<T> computation()?]
- duration:指定的延迟时间。
[FutureOr<T> computation()?]:可不传入computation。
示例: 延迟20秒后执行。
Future.delayed(Duration(seconds: 20),()=>4);
2.3、Future.value()
立即创建一个已完成的Future对象,并携带一个值。
参数:[FutureOr<T>? value]
示例: 携带的值为列表。
Future.value(['Dart',234]);
2.4、Future.error()
立即创建一个已失败的Future对象,并携带指定的错误信息或异常。
参数:
Object error, [StackTrace? stackTrace]
- error: 指定的异常类型。
- [StackTrace? stackTrace] :错误堆栈信息。
示例: 携带的值为列表。
Future.error(Exception('未满18岁!'),StackTrace.current);
2.5、Future.microtask()
将任务加入微任务队列,让它先执行。
参数:FutureOr<T> computation()
示例: 同步任务 --> 微任务 --> 事件任务
void main() {
print('同步任务A');
Future(()=>print('事件任务'));
Future.microtask(()=>print('微任务'));
print('同步任务B');
}
输出:
同步任务A
同步任务B
微任务
事件任务
2.6、Future.sync()
将同步代码和异步代码统一包装为Future。
参数:FutureOr<T> computation()
示例:
Future.sync(
(){
print('同步代码');
Future(()=>1);
});
2.7、async/await语法糖创建
通过语法糖简化异步代码的编写,让编写异步代码和同步代码一样轻松。通过async关键字声明为异步函数,await关键字等待异步操作的完成。
注意: await关键字只能在async声明的异步函数内使用。
示例:
Future<void> dealTask() async {
await Future.delayed(Duration(seconds: 1));
}
三、多个Future的处理
多个Future的处理通过下面四大静态方法实现。
3.1 Future.any()
多个Future中获取最先执行完的那个Future。
示例:
Future.any([
Future.delayed(Duration(seconds: 100),() => print('A')),
Future.delayed(Duration(seconds: 80),() => print('B')),
Future.delayed(Duration(seconds: 40),() => print('C'))
]);
3.2 Future.forEach()
遍历集合中元素,并异步处理。第一个参数为元素集合,第二个为异步函数。
示例:
Future.forEach([1,2,3,4,5], (value) => print(value));
3.3 Future.doWhile()
重复执行异步任务,直到满足终止条件。
示例:
Future.doWhile(()async{
for(int i in [1,9,3,4,5,6,7,8]){
if(i%2==0){
return false;
}
print('i:$i');
};
return true;
});
3.4 Future.wait()
同时执行多个Future,并等待所有Future执行完后返回一个包含所有Future结果的列表。若其中一个失败则会全部失败(可通过eagerError参数调整)。
参数:
Iterable<Future<T>> futures,
{bool eagerError = false, void cleanUp(T successValue)?}
- eagerError: 为true时,当发生第一个错误时终止。
- cleanUp:任务取消时的清理回调。
示例:
Future.wait([
Future((){
print('A');
throw Exception('A异常');
}),
Future((){
print('B');
// throw Exception('B异常');
}),
Future(()=>print('C'))
],eagerError: false,);
四、异步结果的处理
异步结果分为两种,分别为成功结果和错误结果,分别通过then()方法、catchError()方法处理。
- then():成功结果的处理。
- catchError():捕获到错误的处理。
- whenComplete():无论结果成功或失败都会处理。
- timeout():超时熔断。
- onError():类型安全错误处理。
- asStream():将Future转换为单元素Stream。
示例:
Future.delayed(Duration(microseconds: 5000), (){print('异步代码');
throw Exception('错误');})
.then((result) => print('未携带返回结果'))
.catchError((error) => print('$error'))
.whenComplete(() => print('清理资源'))
.timeout(Duration(seconds: 20))
.onError((e,s){print('$e');});
五、总结
本小节我们从Future的定义出发,首先回顾了异步操作是如何不阻塞主线程的,然后介绍了七种创建Future的方式,其次在了解了单个Future后介绍了四种多个Future的处理,最后介绍了异步结果的处理。下面是本小节的归纳总结:
| Future的创建 | 多个Future的处理 | Future结果的处理 |
|---|---|---|
| Future() | Future.any() | then() |
| Future.delayed() | Future.forEach() | catchError() |
| Future.value() | Future.doWhile() | whenComplete() |
| Future.error() | Future.wait() | timeout() |
| Future.sync() | onError() | |
| Future.microtask() | asStream() | |
| async/await语法糖 |