异步Future¶
Future只是异步代码,在一个队列中,还在主线程中。
异步如果有返回值的,返回Future
(未来的数据)。
先保存代码,然后回调的时候再调用,使用then。
方法后面加async
(不加也可以),把耗时的操作(任务)包装到Future
里面。
使用await
会等异步操作完成,这时方法后面需要加async
,把方法包成异步的。
Future¶
Future对象来完成异步操作。
Future工厂构造方法,参数是一个回调函数。函数的执行代码将放入事件队列异步执行。
Future对象可以一直点下去.then .onError .catchError .whenComplete
等等
///1
///2 (1秒后打印的)
///3
void future_Demo() {
print('1'); //主线程
Future(func0); //后台执行
sleep(const Duration(seconds: 1)); //主线程睡眠
print('2');
}
func0() => print('3');
import 'dart:async';
import 'dart:io';
String _data = '0';
void mainTest() {
getData();
}
getData() async {
print('开始data = $_data');
//完整流程 catchError写在最后
Future(() {
//任务 丢进异步里面
//耗时操作
for (int i = 0; i < 10000000; i++) {
throw Exception('网络异常');
}
})
.then(thenFunc)
.whenComplete(() => print('完成了'))
.catchError((e) => print('捕获到了:' + e.toString()));
//不会卡住下面的
print('再干点其它的');
}
FutureOr thenFunc(Null value) {
print('then进来了');
print('结束 data = $value');
}
///结果:
///flutter: 开始data = 0
///flutter: 再干点其它的
///flutter: 完成了
///flutter: 捕获到了:Exception: 网络异常
import 'dart:async';
import 'dart:io';
String _data = '0';
void mainTest() {
getData();
}
getData() async {
print('开始data = $_data');
//异步
//不会卡住下面的
Future future = Future(() {
//任务 丢进异步里面
//耗时操作
for (int i = 0; i < 10000000; i++) {
throw Exception('网络异常');
}
});
future
.then((value) => print('value = $value'))
.onError((error, stackTrace) => print(error.toString()));
future
.whenComplete(() => print('完成了'))
.catchError((e) => print('完成的时候捕获异常:' + e.toString()));
future
.then((value) => print('value = $value'))
.catchError((e) => print('捕获到了:' + e.toString()));
future.catchError((e) => print('使用的时候捕获到了:' + e.toString()));
print('再干点其它的');
}
///打印结果
///flutter: 开始data = 0
///flutter: 再干点其它的
///flutter: Exception: 网络异常
///flutter: 完成了
///flutter: 完成的时候捕获异常:Exception: 网络异常
///flutter: 捕获到了:Exception: 网络异常
///flutter: 使用的时候捕获到了:Exception: 网络异常
Future结果处理
.then
用来注册一个Future完成时要调用的回调。Future里面有return时,.then
回调中的value
才有值。如果里面throw抛出了错误,那么不会调用.then
.whenComplete
在Future完成之后总是会调用,不管是错误导致的完成还是正常执行完毕.catchError
注册一个回调,来捕捉Future的error.catchError
回调只处理原始Future抛出的错误,不能处理回调函数抛出的错误onError
只能处理当前Future的错误
await和async配合¶
如果Future内部代码希望同步执行,则使用await修饰。被async修饰的函数为异步执行。
- await后面的操作必须是异步方法(Future)
- 当前这个函数也必须是异步函数 async修饰的函数
Future后面是任务,要想等任务执行完毕之后再操作,需要加await。
等待await
会卡住下面所有的
如果不想卡住所有的,不使用await,在future.then中加入要等待的任务。
import 'dart:async';
import 'dart:io';
String _data = '0';
void mainTest() {
getData();
}
//方法一:
getData() async {
print('开始data = $_data');
//会卡住下面的
await Future(() {
//任务 丢进异步里面
//耗时操作
for (int i = 0; i < 10000000; i++) {
_data = '网络数据';
}
}).then((value) => print('value = $value')).whenComplete(() => print('完成了'));
print('再干点其它的');
}
///打印结果
///flutter: 开始data = 网络数据
///flutter: value = null
///flutter: 完成了
///flutter: 再干点其它的
//方法二:
getData1() async {
print('开始data = $_data');
//会卡住下面的
//方法后面的会等
await Future(() {
//任务 丢进异步里面
//耗时操作
for (int i = 0; i < 10000000; i++) {
return '网络数据';
}
}).then((value) => print('value = $value')).whenComplete(() => print('完成了'));
print('再干点其它的');
}
///打印结果
///flutter: 开始data = 0
///flutter: value = 网络数据
///flutter: 完成了
///flutter: 再干点其它的
void main() {
testFuture();
//testFuture1();
print('A');
}
void testFuture() async {
Future(() {
sleep(Duration(seconds: 1));
print('C');
}).then((value) => print('D'));
print('B');
}
//打印结果:B A C D
//虽然用了async 但不是异步
void testFuture1() async {
await Future(() {
sleep(Duration(seconds: 1));
print('C');
}).then((value) => print('D'));
print('B');
}
//打印结果:A C D B
//await和async使方法变成了异步的,所以A会先执行
//异步方法里 B会await上面的
加不加async取决于有没有await。
多个Future¶
多任务¶
根据异步代码的添加顺序,任务是有序的,是一个队列,dart单线程。加耗时也是有序的。
void main() {
testFuture();
print('A');
}
void testFuture() async {
Future(() {
return '任务1';
}).then((value) => print('$value结束'));
Future(() {
sleep(const Duration(seconds: 1));
return '任务2';
}).then((value) => print('$value结束'));
Future(() {
return '任务3';
}).then((value) => print('$value结束'));
Future(() {
return '任务4';
}).then((value) => print('$value结束'));
print('任务添加完毕');
}
/**
打印结果:因为没有await 所以不会阻塞下面
flutter: 任务添加完毕
flutter: A
flutter: 任务1结束
flutter: 任务2结束
flutter: 任务3结束
flutter: 任务4结束
任务1 2 3 4必定是有序的。
*/
Future关联关系¶
依赖的链式关系¶
void testFuture1() {
Future(() {
sleep(const Duration(seconds: 1));
return '任务1';
}).then((value) {
print('$value结束');
return '$value任务2';
}).then((value) {
print('$value结束');
return '$value任务3';
}).then((value) {
print('$value结束');
return '$value任务4';
});
}
///flutter: 任务1结束
///flutter: 任务1任务2结束
///flutter: 任务1任务2任务3结束
多任务返回¶
使用Future.wait([futures])
, Future.wait
接收一个Future
对象的列表,并且返回一个新的Future
。该Future
将在列表中所有Future
对象完成后完成。
//多个future结束之后 处理
void testFuture2() {
Future.wait([
Future(() {
print('任务A 执行');
return '任务A';
}),
Future(() {
print('任务B 执行');
return '任务B';
}),
Future(() {
print('任务C 执行');
return '任务C';
}),
]).then((value) => print(value[1] + value[0] + value[2]));
}
//打印结果:
///flutter: 任务A 执行
///flutter: 任务B 执行
///flutter: 任务C 执行
///flutter: 任务B任务A任务C
每个异步任务都是独立执行的,Future.wait
将在它们都完成后继续执行。Future.wait
返回的是一个包含所有结果的列表,这个列表中的结果顺序和传入Future.wait
的Future
列表顺序相同。
所有的异步任务都是并行执行的,而不是顺序执行。这意味着总的等待时间将不会超过最长的那个任务所需的时间,除非其中一个任务抛出了异常。
如果想要处理可能发生的异常,可以给Future.wait
添加onError
回调或者使用try-catch
块。
队列¶
flutter两种队列
- 事件队列
Future放在事件队列
- 微任务队列(scheduleMicrotask)
主线程(外部代码)优先级最高,微任务优先级比Future高
void testFuture3() {
print('外部代码1'); //主线程
//异步
Future(() => print('A')).then((value) => print('A结束'));
Future(() => print('B')).then((value) => print('B结束'));
//异步 微任务
scheduleMicrotask(() {
print('微任务A');
});
sleep(const Duration(seconds: 2)); //外部代码 睡2秒
print('外部代码2'); //主线程
}
/**
结果:
flutter: 外部代码1
flutter: 外部代码2(两秒后)
flutter: 微任务A
flutter: A
flutter: A结束
flutter: B
flutter: B结束
*/
只要是队列就是有序的,无论是事件队列还是微任务队列,都是按照添加的顺序。
事件队列和微任务队列是在同一个线程,串行的。只是微任务比事件队列优先级高。
//队列顺序 5 3 6 1 4 2
void testFuture4() {
Future x1 = Future(() => null);
Future x = Future(() => print('1'));
Future(() => print('2'));
scheduleMicrotask(() => print('3'));
x.then((value) => print('4'));
print('5'); //主线程最先 其它的按照添加的顺序
x1.then((value) => print('6'));
}
.then()
里面的任务相当于放到了微任务队列,所以会先执行then里面的任务,再执行后面的事件队列的任务。
/// 结果
/// flutter: 异步任务1
/// flutter: 微任务添加完毕
/// flutter: 微任务2
/// flutter: 完毕
/// flutter: 微任务1
void futureDemo() {
Future x = Future(() {
print('异步任务1');
//在里面丢一个微任务
scheduleMicrotask(() {
print('微任务1');
});
print('微任务添加完毕');
});
//微任务2先执行
x.then((value) {
print('微任务2');
});
x.whenComplete(() {
print('完毕');
});
}
//队列顺序 5 3 6 8 7 1 4 2
void testFuture4() {
Future x1 = Future(() => null);
x1.then((value) {
print('6');
scheduleMicrotask(() => print('7'));
}).then((value) => print('8'));//then后面的就相当于一个微任务 所以8在7前面
Future x = Future(() => print('1'));
x.then((value) => print('4'));
Future(() => print('2'));
scheduleMicrotask(() => print('3'));
print('5'); //主线程最先 其它的按照添加的顺序
}
//队列顺序 5 3 6 8 7 1 4 2
void testFuture4() {
Future x1 = Future(() => null);
Future x2 = x1.then((value) {
print('6');
scheduleMicrotask(() => print('7'));
});
x2.then((value) => print('8'));
Future x = Future(() => print('1'));
x.then((value) => print('4'));
Future(() => print('2'));
scheduleMicrotask(() => print('3'));
print('5'); //主线程最先 其它的按照添加的顺序
}
//队列顺序 5 3 6 8 7 1 4 10 2 9
void testFuture4() {
Future x1 = Future(() => null);
Future x2 = x1.then((value) {
print('6');
scheduleMicrotask(() => print('7'));
});
x2.then((value) => print('8'));
Future x = Future(() => print('1'));
x.then((value) {
print('4');
Future(() => print('9')); //9是最后添加的,在2后面。
}).then((value) => print('10')); //then是微任务
Future(() => print('2'));//2在9之前添加。
scheduleMicrotask(() => print('3'));
print('5'); //主线程最先 其它的按照添加的顺序
}
微任务放优先级比较高的,不耗时的任务。