主概念:

2:flutter是单线程模型,在没有异步等特殊处理的情况下,代码顺序执行,遇到耗时操作会出现阻塞,因此需要在遇到耗时操作的时候异步处理(也就是放到event队列,也就是使用Future返回,总之一句话,任何使用Future的地方,都是放到event队列执行,其实本质上不是异步执行,而是放在main队列之后执行)

PS:flutter 中的经常把Future叫做异步执行,但是他跟安卓里面的异步是完全不一样的,安卓里面异步是多线程多任务并行,而这边的Future仅仅是把当前任务优先级降低,放到最后执行,本质上还是串行执行任务,Flutter中真正的异步是使用isolate,isolate可以实现任务的并行

3:flutter里面有三个队列,main,microtask,event,执行优先级依次降低,如不以下代码

要搞清代码的执行顺序,首先要把每一行代码属于哪个队列搞清楚,比如上面print(“nick1”), print(“nick3”), print(“nick5”)属于Main队列,因此优先执行,Future.microtask属于microtask队列,后面执行,getbanner里面是Future(event队列),最后执行,因此打印顺序为

Nick1,nick3,nick5,nick4,nick2

4:理解async和await和Future之间的关系

首先是Future

之前说过,main里面是单线程,如果出现耗时操作,那就很尴尬了,主线程会一直卡死,有没有什么办法解决这个问题呢?当然是有,那就是使用Future,一旦创建了Future,那就说明这个任务被放到了event事件队列(event队列是后妈养的,优先级低,最后执行),Future的创建有如下几种

除了以上Future的构造方法创建Future还有一种最常见的创建方法,也就是配合async,看下列代码

以上代码是不是很熟悉?

一旦在某个方法上加了async标记,那么这个方法也会放到event队列执行,这个方法要么没返回值,有返回值的话必须是Future类型,否则报错,因此async和Future就是强绑定关系,async的中文翻译就是异步的意思

PS:现在往event队列添加事件的方法有两个,一个是使用Future的构造创建Future,另一个就是在方法上添加async标记(此描述有问题,涉及到比较复杂的逻辑,暂时先这么理解,后面还有进一步的完善和介绍)

搞清楚了Future和async的用法和关系之后,再来看await,为什么有这个东西的出现?

首先要知道await的作用是什么,顾名思义,等待,等待前面执行完,获得结果,再执行后面的代码,比如请求网络,获得结果,再渲染页面

那么为什么使用await关键字之后,框架会要求你把这个方法标记为async异步呢,不标记就报错!

这个问题困扰我多年,经过我反复思考揣摩,大概知道原因在哪

这是出于安全性考虑,因为await的作用是等待执行,会阻塞后面的代码,如果允许在main队列里面使用,会阻塞主线程,这是系统框架所不允许的,但是异步方法体(event队列)的执行优先级本身就是最低的,因此,可以在异步方法体里面执行await等待操作(反正main里面任务都执行完了,你想等就等吧)

这是flutter框架进行的安全性拦截,也就是说,你想要执行等待操作,只能在event事件里面等待,不能在main事件里面等待

关于async和await的精辟总结

async:用来表示函数的异步的,定义的函数会返回一个Future对象。

await:后面跟着一个Future,表示等待该异步任务完成后才会继续往下执行。await只能出现在异步函数内部。能够让我们可以像写同步代码那样来执行异步任务而不使用回调的方式。

下面再做几个实例分析,哪些地方可以用await,使用await会带来哪些影响

结果如下

这是书城里面加载书架的一段代码,loadData里面加了一个await,那就必须把这个方法标记为async,那就意味着,这个方法已经被丢进event队列,整个loadData方法就会在main方法执行完再执行,我们测试一下

首先去除loadData的async和await标记,查看打印日志

下面我们把loadData的await和async去掉,再看打印日志

以上两种情况几乎涵盖了所有异步同步执行的顺序,一定要会分析

再做最后的总结

分析代码的执行顺序,第一步,识别哪些代码属于main,哪些代码属于microtask,哪些代码属于event事件

这边有一个点之前理解有问题,之前提到创建异步有两个方法

以上说法实际上不对,如果使用Future的构造创建event事件,那这个事件一定是在main全部执行完再执行,但是使用async标记方法来创建异步的时候,如果async方法体内部没有出现await,那么这个async是无效的,该方法并不是异步方法,也不会丢到event队列执行,他还是会在main里面执行

如果async方法里面某个地方加了await,那么await之前的代码还是在main上顺序执行,await之后的代码会丢到event队列里面等待执行

所以,async方法体里面如果没有await,那么就没有意义,可以删除该标记

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐