什么是future
future类似android中的handler,表示稍后做的任务
使用如下:
Future((){
print('future do..');
return '1';
}).then(print);
print('main end');
可以看到main end先打印,然后打印future里面的任务,最后then打印结果
main end
future do..
1
future 异常捕获
future的异常处理有两方法catchError和onError,
catchError(Function onError, {bool test(Object error)?})
onError<E extends Object>(
FutureOr<T> handleError(E error, StackTrace stackTrace),
{bool test(E error)?})
如果发生异常了,那么then方法就不会被调用,但是whenComplete方法最终也会被调用,类似于Java里面的finally。
异常示例代码如下:
Future((){
throw Exception('this is error');
}).then((v){
print(v);
})
.whenComplete(() => print('done'));
print('main end')
输出异常
main start
main end
done
Unhandled exception:
Exception: this is error
加上catchError后,
Future((){
throw Exception('this is error');
}).then((v){
print(v);
})
.catchError((e,stackTrace){
print('catch Error: $e');
})
.whenComplete(() => print('done'));
print('main end');
输出如下,可以看到catchError捕获到了异常,参数e为异常对象,参数stackTrace为当前堆栈信息
main start
main end
catch Error: Exception: this is error
done
catchError方法还有个可选参数 {bool test(Object error)?},表示如果我只想捕获某种类型的异常,
代码如下,表示我只捕获FileSystemException类型异常
Future((){
throw Exception('this is error');
}).then((v){
print(v);
}).catchError((e){
print('catch Error: $e');
},test: (e)=>e is FileSystemException)
.whenComplete(() => print('done'));
print('main end');
输出异常如下,异常没有捕获到
main start
main end
Unhandled exception:
Exception: this is error
done
onError是Future的扩展方法,内部也是调用的catchError方法
Future<T> onError<E extends Object>(
FutureOr<T> handleError(E error, StackTrace stackTrace),
{bool test(E error)?}) {
// There are various ways to optimize this to avoid the double is E/as E
// type check, but for now we are not optimizing the error path.
return this.catchError(
(Object error, StackTrace stackTrace) =>
handleError(error as E, stackTrace),
test: (Object error) => error is E && (test == null || test(error)));
}
构造方法microtask,sync同Future({})使用相同,区别就是Future把任务放在事件队列,microtask把任务放在微任务队列
Future((){
print('future do..');
return '1';
}).then(print);
Future.microtask((){
print('microtask do');
return '4';
} ).then(print);
Future.sync(() {
print('sync do');
return '5';}).then(print);
print('main end');
输出
main start
sync do
main end
2
microtask do
4
5
future do..
1
Process finished with exit code 0
等待超时timeout
timeout(Duration timeLimit, {FutureOr<T> onTimeout()?})
设置超时时间,如果任务超时了,如果onTimeout参数有设置,调用onTimeout,如果onTimeout参数没设置,直接抛出TimeoutException异常
Future(()async{
await Future.delayed(Duration(seconds: 2));
return 'a';
}).timeout(Duration(seconds: 1),onTimeout: ()=>'time out').then(print).whenComplete(() => print('done'));
输出
time out
done
构造方法delay:表示延迟任务
如下表示延迟1s后执行return
Future.delayed(Duration(seconds: 1),(){
return '3';
});
构造方法error,抛出一个异常
print('main start');
var v = await getComplete(1,0);
print('main end');
Future<int> getComplete(int a,int b){
if(b == 0){
return Future.error(Exception('b cannot 0'));
}
return Future.value(a~/b);
}
输出如下,可以看出程序非正常退出了,在await那行就抛出了异常。这就要求调用getComplete方法的地方一定要处理异常
main start
Unhandled exception:
Exception: b canot 0
Process finished with exit code 255
静态方法wait,等待多个future结果
Future<List<T>> wait<T>(Iterable<Future<T>> futures,
{bool eagerError = false, void cleanUp(T successValue)?}
int start = DateTime.now().millisecondsSinceEpoch;
List<dynamic> value = await Future.wait<dynamic>([
delayedNumber(1),
delayedString("a"),
delayedNumber(1),
delayedString('b'),
]);
int cost = DateTime.now().millisecondsSinceEpoch-start;
print("cost:${cost/1000} s, value:$value");
//模拟耗时,延迟3秒
Future<int> delayedNumber(int num) async {
await Future.delayed(const Duration(seconds: 3));
return 2;
}
//模拟耗时,延迟2秒
Future<String> delayedString(String value) async {
await Future.delayed(const Duration(seconds: 2));
return value;
}
输出结果如下,可以看出最终耗时并不是几个future的总和,而是最大的耗时任务,相当于并行处理
cost:3.025 s, value:[2, a, 2, b]
静态方法any,执行多个future,只要有一个完成就返回结果
同样是上述代码,把wait换成any,返回值就不是list了,因为只有一个结果会返回
int start = DateTime.now().millisecondsSinceEpoch;
dynamic value = await Future.any<dynamic>([
delayedNumber(1),
delayedString("a"),
delayedNumber(1),
delayedString('b'),
]);
int cost = DateTime.now().millisecondsSinceEpoch-start;
print("cost:${cost/1000} s, value:$value");
输出结果,返回的用时最小的a
cost:2.019 s, value:a
静态方法forEach,对集合每个元素执行action操作
forEach<T>(Iterable<T> elements, FutureOr action(T element))
同时这个方法的调用then是拿不到数据的
示例代码如下
print('main start');
Future.forEach([1,2,3,4], (element) {
print(element);
return 'a';
}).then((value) => print(value));
print('main end');
输出,可以看出,和正常的集合遍历没啥区别,而且是立马执行的
main start
1
2
3
4
main end
null
修改代码action返回值为future,其他不变,
Future.forEach([1,2,3,4], (element) {
print(element);
return Future.value('a');
}).then((value) => print(value));
输出如下,可以看到除了第一个元素,后面的元素在稍后执行
main start
1
main end
2
3
4
null
静态方法doWhile:返回为true时会一直重复,直到返回false
适合用在有轮询情况的业务,没有达到条件就一直轮询
示例如下,当value为3时才执行then语句
Future task = Future.doWhile(()async{
await Future.delayed(const Duration(seconds: 1));
value++;
if (value == 3) {
return false;
}
return true;
});
task.then((_){
print('Finished with $value');
});
输出
Finished with 3
Completer
如果我们写的一个方法A返回的是Future类型,,但是我们A方法里面调用了B方法,B方法是个异步方法,但是B方法返回是利用回调返回,
这种场景比较常见我们调用其他人的异步方法时,如果这个异步方法返回的是Future,那我们可以直接用await获取异步结果,但是如果不是,这个时候如果我们还想用Future返回,就可以用Completer了
例子如下,call方法通过callback回调结果,
Future<int> testCompleter(){
Completer<int> c = Completer();
call((d){
c.complete(d);
});
return c.future;
}
void call(Function callback){
Future.delayed(Duration(seconds: 1),(){
callback(123);
});
}
print('main start');
testCompleter().then(print);
print('main end');
输出
main start
main end
123
Process finished with exit code 0