Flutter--Future原理
Flutter--Future
什么是Future?
简单来说future就是一个Future<T>对象,当执行return await。。。的时候,实际上返回的是一个延迟计算的Future对象,这个Future对象是Dart内置的,有自己的队列策略,它将要操作的事件放入EventQueue中,在队列中的事件按照先进先出的原则去逐一处理事件,当事件处理完成后,将结果返回给Future对象。
在这个过程中涉及到了异步和等待:
- 异步:就是不用阻塞当前线程,来等待该线程任务处理完成再去执行其他任务。
- 等待:await,声明运算为延迟执行
async和await
首先看一个例子:
getData() async{
return await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
}
//然后调用函数来获取结果
String data = getData();
这段代码在运行的时候会报错。
因为data
是String
类型,而函数getData()
是一个异步操作函数,其返回值是一个await
延迟执行的结果。
在Dart
中,有await
标记的运算,结果都是一个Future
对象,Future
不是String
类型,所以就报错了。
如何获取异步函数的结果呢?Dart
规定有async
标记的函数,只能由await
来调用,那么我们可以在函数前加一个await
关键字:
String data = await getData();
但是这违背了await
必须要在async
标记的函数中使用,所以赋值代码可以改成:
String data;
setData() async {
data = await getData(); //getData()延迟执行后赋值给data
}
总结:
async
和await
的使用其实就只有两点:
-
await
关键字必须在async
函数内部使用 - 调用
async
函数必须使用await
关键字
Dart异步
Dart是单线程模型,是一种Event-Looper以及Event-Queue的模型,所有的事件都是通过EventLooper的依次执行。
Event Loop的执行顺序
-
从EventQueue中获取Event
-
处理Event直到EventQueue为空
imageEvent即事件,包括输入,点击,Timer,文件IO等
image
单线程模型
所谓单线程,就是一旦一个函数开始执行,就必须将这个函数执行完,才能去执行其他函数。
Dart中没有线程的概念,只有isolate,每个isolate都是隔离的,并不会共享内存。一个Dart程序是在Main isolate中的main函数开始,而在Main函数结束后,Main isolate线程开始一个个(one by one)的处理Event Queue中的每一个Event。
imageEvent Queue、Microtask Queue
Dart中的Main Isolate只有一个Event Looper,但是存在两个Event Queue:
-
Event Queue
-
Microtask Queue
image
这两者之间的关系可以用一张图来说明:
- Microtask Queue中的Event优先被处理
- 直到Microtask Queue队列中的Event为空时,才会去执行Event Queue中的Event
异步任务调度
当有代码可以在后续任务执行的时候,有两种方式,通过dart:async这个Lib中的API即可:
- 使用Future类,可以将任务加入到Event Queue的队尾
- 使用scheduleMicrotask函数,将任务加入到Microtask Queue队尾
当使用EventQueue时,需要考虑清楚,尽量避免microtask queue过于庞大,否则会阻塞其他事件的处理
imageFuture的使用
一般常用的Future构造函数:
new Future((){
// doing something
});
而一般常用的还有当有分治任务时,需要将一个大任务拆成很多小任务一步步执行时,就需要使用到Future.then函数来拆解任务:
void main(){
new Future(() => futureTask) // 异步任务的函数
.then((m) => "futueTask execute result:$m") // 任务执行完后的子任务
.then((m) => m.length) // 其中m为上个任务执行完后的返回的结果
.then((m) => printLength(m))
.whenComplete(() => whenTaskCompelete); // 当所有任务完成后的回调函数
}
int futureTask() {
return 21;
}
void printLength(int length) {
print("Text Length:$length");
}
void whenTaskCompelete() {
print("Task Complete");
}
当任务需要延迟执行时,可以使用new Future.delay来将任务延迟执行,而如上所述,只有当Main isolate的Event Queue处于Idle的状态时,才会延迟1s执行,否则等待的时间会比1s长很多
new Future.delayed(const Duration(seconds: 1), () => futureTask);
Tips
-
Future
中的then
并没有创建新的Event
丢到Event Queue
中,而只是一个普通的Function Call
,在FutureTask
执行完后,立即开始执行 - 当
Future
在then
函数先已经执行完成了,则会创建一个task
,将该task
的添加到microtask queue
中,并且该任务将会执行通过then
传入的函数 -
Future
只是创建了一个Event
,将Event
插入到了Event Queue
的队尾 - 使用
Future.value
构造函数的时候,就会和第二条一样,创建Task
丢到microtask Queue
中执行then
传入的函数 -
Future.sync
构造函数执行了它传入的函数之后,也会立即创建Task
丢到microtask Queue
中执行