继续Dart语言的学习,这次过后下次就进入全新的Flutter的学习了,小小的激动。。
操作符重载:
C++中也有,咱们来看一下在Dart中是如何来实现的:
比较简单。
异步【重要!】:
async和await:
- await关键字必须在async函数内部使用。
- await表达式可以使用多次。
看着很自然,接下来再来改造一下,就变得不太好理解了。。
这是为啥呢?下面来剖析一下:
背后其实有一个事件队列,其中main()的执行总是从上往下顺序执行的,当遇到await时,则会将方法添加到队列中,也就是:
此时会将getStr()添加到事件队列中,然后并返回Future,此时的:
然后又加到main()的主流程继续往下执行了,所以:
当整个main()方法都执行完之后,最后再来执行:
有点难理解,为了加深其理解,下面进一步再改造:
好,下面再来分析一下:
然后main()流程往下执行完,所以:
接着再执行:
而此时返回main()由于已经没有代码了,所以最后则将剩下的给执行完了,如下:
这块不是很好理解,但是必须得要了解,因为在未来实际项目中异步会大量用到。
then,catchError,whenComplete:
- 如果需要监听“完毕”这个状态,那么用whenComplete,需要监听“成功”这个状态,用then,需要监听“失败”这个状态,用catchError。
- 如果重写了test方法,test返回true就可以在catchError的onError方法里捕获到异常,如果test返回false,就把该异常继续抛出而不会在catchError方法里被捕获,如果不写test默认实现一个返回true的test方法
咱们来试一下:
咱们也可以catchError一下:
然后看一下catchError的源码:
咱们来使用一下:
Event-Looper:
- 一个消息循环的职责就是不断从消息队列中取出消息并处理他们直到消息队列为空。
- 消息队列中的消息可能来自用户输入,文件I/O消息,定时器等。例如上图的消息队列就包含了定时器消息和用户输入消息。
- Dart中的Main Isolate只有一个Event Looper,但是存在两个Event Queue: Event Queue以及Microtask Queue。
说到Looper就想到了Android中的Looper了,基本上差不多的意思,看一个示例图:
Event-Queue和Microtask Queue:
- 优先全部执行完Microtask Queue中的Event。
- 直到Microtask Queue为空时,才会执行Event Queue中的Event。
- 当Event Looper正在处理Microtask Queue中的Event时候,Event Queue中的Event就停止了处理了,此时App不能绘制任何图形,不能处理任何鼠标点击,不能处理文件IO等等。
- 绘制图形,处理鼠标点击,处理文件IO等都是在Event Queue里完成的。
看一下示意图:
任务调度:
- 优先全部执行完Microtask Queue中的Event。
- 直到Microtask Queue为空时,才会执行Event Queue中的Event。
new Future():
下面来看一个很好理解上面东东的代码:
这代码看着好晕哦。。但是也得硬着头皮来理解,还是很重要的。
接着就是集中来分析一个整个流程。
此时就会将其放到队列当中:
以此类推:
也相继入队:
好,接下来三个Future都调了then,如下:
最后是打印f7:
接着则按入队的顺序来执行,所以此时就执行到:
输出为:
继续:
那此时就会输出了:
接下来则再到:
此时这个Future的then干的事比较多,不要着急,一步步来分析:
所以:
由于f1已经在之前执行过了一次then,执行完了,如下:
所以此时再执行then则会将其放到微队列【如上面所说的Microtask】来:
而微队列的优先级别比较高,如果发现有数据则会立马打印,所以:
此时f2.then()的代码就执行完了:
好,接下来再执行f3.then了:
最后再执行f4:
呃,真的好麻烦呀。。理解了这个程序的运行结果,那上面的各种理论就比较好理解了,所以理解它非常之重要。
scheduleMicrotask():
- 如果可以,尽量将任务放入event队列中。
- 使用Future的then方法或whenComplete方法来指定任务顺序。
- 为了保持你app的可响应性,尽量不要将大计算量的任务放入这两个队列。
- 大计算量的任务放入额外的isolate中。
接下来升级一下程序,再来瞅下:
先直接run一下,省下脑细胞:
面对这样变态的程序,真的是没有一点分析的动力,但是现在还是打基础的阶段,木办法,只能咬牙坚持,下面还是一步步来分析其过程:
所以接下来就是重点分析future相关的执行流程:
而由于微对队的优先级比事件队列的优先级要高,所以立马会打印它,所以:
此时微队列就空了:
接着继续往下分析:
而最底下还有一个微任务,不管怎么样它比Future都要早执行,所以;
此时微队列为:
然后会立马输出,如下:
此时微队列又被清空了,形态现在变为:
接下来再集中来分析事件队列的顺序了:
其事件队列为:
此时要注意啦!!!有then的情况下是需要先将then全部执行完之后,再来执行微任务,不要看到微任务就立马输出,因为微任务是在then中创建的,先要将then执行完,所以输出为:
所以此时的队列情况为:
在then整个都执行完之后,看到微任务队列中还有,则才开始执行它,所以:
此时微队列又空了:
接下来则执行下一个Future:
将其入队:
所以接下来则会按队列先后顺序来执行,所以会输出:
理解了上面两个例子,就对Dart的异步任务就比较了解了。
生成器:
同步生成器:
- 使用sync*,返回的是Iterable对象。
- yield会返回moveNext为true,并等待 moveNext 指令。
- 调用getSyncGenerator立即返回Iterable对象。
- 调用moveNext方法时getSyncGenerator才开始执行。
如何来理解这个程序呢?
直有调用了这个代码才会执行:
为了更加清楚的看到整个执行过程,咱们debug打断点看一下是否如我们所描述的那样:
这个流程真得挺逆天的,完全不是按正常思维来的,记住吧。。
异步生成器:
- 使用async*,返回的是Stream对象。
- yield不用暂停,数据以流的方式一次性推送,通过StreamSubscription进行控制。
- 调用getAsyncGenerator立即返回Stream,只有执行了listen,函数才会开始执行。
- listen返回一个StreamSubscription 对象进行流监听控制。
- 可以使用StreamSubscription对象对数据流进行控制。
看一下代码:
这里debug看一下其执行过程:
反正,我是已经懵逼了,先有个大体认识吧,具体在未来的项目中再来熟悉这样的用法。
递归生成器:
yield* 以指针的方式传递递归对象,而不是整个同步对象。
下面看下代码:
这块了解下用法就成,比较难理解。
隔离-Isolates:
- Dart没有共享内存的并发,没有竞争的可能性所以不需要锁,也就不用担心死锁的问题。
- isolate之间没有共享内存,所以他们之间的通信唯一方式只能是通过Port进行,而且Dart中的消息传递总是异步的。
- isolate神似Thread,但实际上两者有本质的区别。操作系统内的线程之间是可以有共享内存的而isolate没有,这是最为关键的区别。
所有Dart代码都在隔离区内运行,而不是线程。每个隔离区都有自己的内存堆,确保不会从任何其他隔离区访问隔离区的状态。
这里了解一下概念既可,也就是我们在main()其实不是运行在线程当中的,跟Java是不一样的。
元数据(注解):
过一下既可,跟Java类似。
@deprecated:
@override:
自定义:
- 在java中,如果自定义一个注解,需要添加 @Target 作用域注解,@Retention 注解类型注解,添加 @interface,然后定义注解参数。
- 构造方法定义为编译时常量。
只是自定义方式跟Java的是有一些区别的,下面来自定义一下:
注意:上面这个类是一个自定义注解,别以为是一个普通的类哈,接下来可以应用一下它:
至此,整个Dart语言的学习就暂且到这了,真的是很枯燥,但是少了这个内功在Flutter的学习又不行,所以整体把Dart过了一遍,不可能记得住,但是有个整体的入门之后会在未来Flutter的学习走得更加的踏实。。