小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
之前在找工作时,被问到过两次“你是怎么理解Future的”,其实突然冷不丁的被这么一个抽象的问题一问还挺懵的,其实面试官无非就想看看你平时是怎么用的Future,Future的工作原理是什么样的。今天就总结一下自己对Future的理解以及一些用法。
原理
Future对象可以用来表述一个异步任务的执行,在之前的文章中说,Dart是单线程模型,程序拥有一个Event Loop消息队列,在队列中不断循环查询是否有microtask
微任务队列和event queue
事件队列,microtask
的优先级总是高于event queue
。那么在程序中执行到Future时,Dart会将异步任务的函数执行体放入event queue
中,然后立即返回去执行后面的代码。当同步执行的代码执行完毕后,event queue
会按照加入event queue
的顺序(即声明顺序),依次取出事件,最后同步执行 Future
的函数体及后续的操作,所以并不会发生阻塞的问题。如: _testFuture
方法并没有影响后面print的打印。
async/await
如上面的_testFuture方法加入了async
关键字,证明这个函数是异步执行的,执行调用不会阻塞_testFuture方法后面的代码执行。而在方法调用前如果加入了await
关键字,则此方法就变成了一个同步方法,需要等待执行结果才可以执行后面的代码,而await和async是成对出现的,有await就一定要有async。
可以看到print("执行Future后面的代码");
这句话是在testFuture方法同步执行完毕后才调用的。
常用方法
Future.value()
表示创建一个返回value中的值得Future,如:
Future _testFuture() async {
return Future.value("hello world");
}
void main() async{
print("程序开始");
String message = await _testFuture();
print(message);
print("执行Future后面的代码");
}
控制台:
程序开始
hello world
执行Future后面的代码
复制代码
Future.delayed()
上面的例子中就用到了此方法用来模拟延时操作,当你需要延时处理时如闪屏页的倒计时跳转,就可以使用该方法。
Future.delayed(Duration(milliseconds: 3000), () {
/// 跳转至首页
});
复制代码
Future.then()
Future异步任务结束后的回调,返回值仍是一个Future,所以我们可以在then方法后放置多个then,放置多个then时只有当前面的then函数执行完毕后后面的then才会回调到,也就是会顺序执行。
Future.delayed(Duration(milliseconds: 1000), () {
print("111");
}).then((value){
print("222");
}).then((value){
print("333");
});
控制台:
111
222
333
复制代码
Future.catchError()
此方法用来捕获Future执行异常错误,需要注意的是,如果catchError写在then方法前面执行then方法是可以调用到的,如果写在then方法后面则then方法中的代码不会执行,所以在使用时一定要注意逻辑顺序。

Future.whenComplete()
此方法表示Future异步执行完毕后一定会调用的方法,不管是否有异常情况。
Future.delayed(Duration(milliseconds: 100), () {
throw NullThrownError();
}).then((value){
print("222");
}).catchError((error){
print(error);
}).whenComplete((){
print("333");
});
控制台:
程序开始
Throw of null.
333
复制代码
进阶方法
Future.foreach()
根据传入的集合,从中取值并创建集合长度个数的Future并顺序执行。
Future.forEach([1,2,3], (element) => print(element));
控制台:
程序开始
1
2
3
复制代码
Future.timeout()
如果你希望一个异步任务在固定时间内回调,没有回调回来就出现错误,那么使用这个方法可以满足要求。
Future.delayed(Duration(milliseconds: 2000), () {
print("111");
}).then((value){
print("222");
}).timeout(Duration(milliseconds: 1000));
控制台:
程序开始
Unhandled exception:
TimeoutException after 0:00:01.000000: Future not completed
复制代码
Future.wait()
传入多个Future的集合,当这些任务全部执行完成时Future.wait将所有执行结果统一返回.非常适合在某些场景下,一个数据的显示依赖于多个网络接口返回时就可以使用此方法。
Future future1 = Future.value(1);
Future future2 = Future.value(2);
Future future3 = Future.value(3);
Future.wait([future1,future2,future3]).then((value) =>
print("全部执行完毕${value[0]} ${value[1]} ${value[2]}"));
控制台:
程序开始
全部执行完毕1 2 3
复制代码
Future.any()
传入一个集合,从中取值并创建集合长度个数的Future并顺序执行并返回第一个执行完成的结果。
Future future1 = Future.value(1);
Future future2 = Future.value(2);
Future future3 = Future.value(3);
Future.any([future1,future2,future3]).then((value) =>
print("第一个执行完毕的:$value")
);
控制台:
程序开始
第一个执行完毕的:1
复制代码
以上就是自己对Future的总结,如有错误,还望指出