简介
因为Dart是单线程的语言,所以如果线程中顺序执行的时候如果遇到一些耗时阻塞的操作,比如数据请求,延时操作等,就会产生卡顿,所以用异步来解决。 异步代码主要是用async await实现,熟悉js的同学应该非常熟悉,这里的使用方法也和js很像
异步 async 和 await
我们先来看一个例子:
void main(){
getName1();
getName2();
getName3();
}
/**
* 注意事项
* 1、await关键字必须在async函数内部使用
* 2、await表达式可以使用多次
*/
Future getName1() async {
await getStr1();
await getStr2();
print('getName1’);
}
getStr1() {
print('getStr1’);
}
getStr2() {
print('getStr2’);
}
getName2() {
print('getName2’);
}
getName3() {
print('getName3’);
}
运行结果如下:
getStr1
getName2
getName3
getStr2
getName1
我们来分析一下:
getName1 我们使用
async做了标记,表示函数内部包含有延迟执行的代码,而await标记的方法就是需要延迟执行的,会将其放入延迟的队列中。getName2和getName3 我们并没有做类似的标记,说到这相信大家都明白运行结果的由来了
异步-then,catchError,whenComplete
void main() {
new Future(() => futureTask())//异步任务的函数
.then((m) => "result:$m")//任务执行完后的子任务
.then((m) => m.length) //其中m为上个任务执行完后的返回的结果
.then((m) => printLength(m))
.catchError(print)
.whenComplete(() => whenTaskCompelete());//所有任务完成后的回调函数
}
如果需要监听“完毕”这个状态,那么用whenComplete,需要监听“成功”这个状态,用then,需要监听“失败”这个状态,用catchError。 如果重写了test方法,test返回true就可以在catchError的onError方法里捕获到异常,如果test返回false,就把该异常继续抛出而不会在catchError方法里被捕获,如果不写test默认实现一个返回true的test方法
异步-new Future()
void main(){
testFuture(); /// f7 f1 f6 f3 f5 f2 f4
}
void testFuture() {
Future f = new Future(() => print('f1'));
Future f1 = new Future(() => null);
//Future f1 = new Future.delayed(Duration(seconds: 1) ,() => null);
Future f2 = new Future(() => null);
Future f3 = new Future(() => null);
f3.then((_) => print('f2'));
f2.then((_) {
print('f3');
new Future(() => print('f4'));
f1.then((_) {
print('f5');
});
});
f1.then((m) {
print('f6');
});
print('f7');
}
- 使用new Future将任务加入event队列
- Future中的then并没有创建新的Event丢到Event Queue中,而只是一个普通的Function Call,在FutureTask执行完后,立即开始执行
- 如果在then()调用之前Future就已经执行完毕了,那么任务会被加入到microtask队列中,并且该任务会执行then()中注册的回调函数
- 使用Future.value构造函数的时候,就会上一条一样,创建Task丢到microtask Queue中执行then传入的函数
- Future.sync构造函数执行了它传入的函数之后,也会立即创建Task丢到microtask Queue中执行
- 当任务需要延迟执行时,可以使用new Future.delay()来将任务延迟执行
异步-scheduleMicrotask()
import 'dart:async';
void main(){
testFuture();
}
void testScheduleMicrotask(){
scheduleMicrotask(() => print('s1'));
new Future.delayed(new Duration(seconds: 1), () => print('s2'));
new Future(() => print('s3')).then((_) {
print('s4');
scheduleMicrotask(() => print('s5'));
}).then((_) => print('s6'));
new Future(() => print('s7'));
scheduleMicrotask(() => print('s8'));
print('s9');
}
- 如果可以,尽量将任务放入event队列中
- 使用Future的then方法或whenComplete方法来指定任务顺序
- 为了保持你app的可响应性,尽量不要将大计算量的任务放入这两个队列
- 大计算量的任务放入额外的isolate中
生成器-同步生成器
Main(){
var it = getSyncGenerator(5).iterator;
while (it.moveNext()) {
print(it.current);
}
}
Iterable<int> getSyncGenerator(int n) sync* {
print('start');
int k = 0;
while (k < n) {
yield k++;
}
print('end');
}
- 使用sync*,返回的是Iterable对象
- yield会返回moveNext为true,并等待 moveNext 指令
- 调用getSyncGenerator立即返回Iterable对象
- 调用moveNext方法时getSyncGenerator才开始执行
生成器-异步生成器
Main(){
//getAsyncGenerator(5).listen((value) => print(value));
StreamSubscription subscription = getAsyncNumIterator(5).listen(null);
subscription.onData((value) {
print(value);
if(value>=2){
subscription.pause();
}
});
}
Stream<int> getAsyncGenerator(int n) async* {
print('start');
int k = 0;
while (k < n) {
yield k++;
}
print('end');
}
- 使用async*,返回的是Stream对象
- yield不用暂停,数据以流的方式一次性推送,通过StreamSubscription进行控制
- 调用getAsyncGenerator立即返回Stream,只有执行了listen,函数才会开始执行
- listen返回一个StreamSubscription 对象进行流监听控制
- 可以使用StreamSubscription对象对数据流进行控制