==============================================================================
(这部分的内容主要来自泪已无痕:[译] Flutter 异步编程:Future、Isolate 和事件循环,原文更详细,这里是完全参考着他写的,详细了解建议看原文。)
Dart是单线程模型,而Flutter则依赖于Dart,单线程模型有一个问题:同一时间执行一个操作,而其他的操作只能再其之后执行。
我们知道在Android中不能写死循环,否则会导致ANR,而Flutter也是一样,在Dart中如果我们写一个很大的for循环,那么在循环中执行操作同样会导致线程的阻塞,界面也被阻塞,例如在重写的setState()中执行循环,则必须等到结束后才能加载出界面。
但是在如今纷繁复杂的业务逻辑要求中,我们单线程模型实际上很难满足各种各样的需求了。所以,Dart采用了了一个代码序列器(事件循环)。
当我们启动一个DartApp时,将会构建一个新的线程进程,在Dart中为Isolate
,该线程将是你在整个应用中唯一需要关注的。
所以,此线程创建后,Dart将会自动地:
-
初始化2个FIFO队列(MicroTask和Event)
-
并且当该方法执行完成后,执行Main方法
-
启动
事件循环
事件循环
是一种无限循环,在每个时钟周期内,如果没有其他的Dart代码执行,则:
void eventLoop(){
while (microTaskQueue.isNotEmpty){
fetchFirstMicroTaskFromQueue();
executeThisMicroTask();
return;
}
if (eventQueue.isNotEmpty){
fetchFirstEventFromQueue();
executeThisEventRelatedCode();
}
}
从先后顺序我们可以看出,MicoTask队列
优先于Event队列
。
5.1 MicroTask队列
MicroTask
队列用于非常简短且需要异步执行的的内部动作,这些动作需要在其他事件完成后 并 在将执行权交给Event
队列之前运行。
5.2 Event队列
Event 队列适用于以下参考模型:
-
IO
-
手势
-
绘图
-
计时器
-
流
-
futures
事实上,每次外部事件被触发时,需要执行的代码都会被Event队列所引用。一旦没有MicroTask
运行,事件循环将考虑Event队列中的第一项并执行它,而Future操作也将由Event队列执行。
5.3 Future
Future是一个异步执行并且在未来某一个时刻完成或者失败的任务,当实例化一个Future时:
-
该Future的实例被创建、并记录在由Dart管理的内部数组中。
-
需要由此Future执行的代码直接推送到Event中。
-
该Future实例返回一个状态(=incomplete)
-
如果存在下一个同步代码,则执行它。
只要事件循环
从Event
循环中获取它,被Future
引用的代码将像其他任何Event
一样执行。
当改代码将被执行完成(或者失败)时,then或者cacheError回调将被触发。
在如下例子中:
void main(){
print(‘Before the Future’);
Future((){
print(‘Running the Future’);
}).then((_){
print(‘Future is complete’);
});
print(‘After the Future’);
}
输出的顺序:
Before the Future
After the Future
Running the Future
Future is complete
执行的流程:
-
print(‘Before the Future’)
-
将 (){print(‘Running the Future’);} 添加到 Event 队列;
-
print(‘After the Future’)
-
事件循环获取(在第二步引用的)代码并执行它
-
当代码执行时,它会查找 then() 语句并执行它
所以,Flutter/Dart是使用Event循环机制来模拟并发的请求的。
Aysnc方法在使用时,Dart会认为该方法的返回值是一个Future,它同步执行该方法,直到遇到第一个await关键字,然后它暂停该方法其他部分的执行,一旦await关键字引用的Future执行完成,下一行代码将立即执行。
例如这个例子:
void main() async {
methodA();
await methodB();
await methodC(‘main’);
methodD();
}
methodA(){
print(‘A’);
}
methodB() async {
print(‘B start’);
await methodC(‘B’);
print(‘B end’);
}
methodC(String from) async {
print(‘C start from $from’);
Future((){ // <== 该代码将在未来的某个时间段执行
print(‘C running Future from $from’);
}).then((_){
print(‘C end of Future from $from’);
});
print(‘C end from $from’);
}
methodD(){
print(‘D’);
}
从Main方法开始执行,遇到第一个await则暂停,按照以往的认知,打印应该是:
A
B start
C start from B
C running Future from B
C end of Future from B
C end from B
B end
C start from A
C running Future from A
C end of Future from A
C end from A
D
但是其实是:
A
B start
C start from B
C end from B
— C中的Future代码会在之后执行,不会立即执行。
B end
C start from main
C end from main
D
—到此处代码执行完了,才开始执行Event中的代码
C running Future from B
C end of Future from B
C running Future from main
C end of Future from main
这和我们想象的多线程(异步)处理有点不一样,异步只是线程各自以未知的顺序向前推进,但是单线程的Dart依靠事件循环机制
,模拟了异步操作,但是我们发现所有的Future都放到了代码的最后执行。预测程序执行变得非常困难。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数软件测试工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上软件测试开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
)]
[外链图片转存中…(img-VesRJYxN-1712953440722)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上软件测试开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
[外链图片转存中…(img-JZi9a89R-1712953440722)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!