【Flutter】Future, async, await
Dart 为单线程语言,但它提供了异步编程的方式,Future, async, await 为异步编程的类和关键字,
Future
Future.then
异步编程最常用的场景是访问网络接口,返回数据,这里我们模拟这样的场景,2秒后返回网络数据,代码如下:
Future<String> getMyName() {
Future.delayed(Duration(seconds: 2), () => '老孟');
}
下面将获取到的数据打印出来,
void _incrementCounter() {
var name = getMyName();
print('name:$name');
}
上面的用法是典型的错误用法,而且也是大部分初学者容易犯错的地方,getMyName 为 Future 方法,表示此方法为异步方法。
上面的代码打印日志如下:
flutter: name:Instance of 'Future<String>'
正确的用法如下:
void _incrementCounter() {
getMyName().then((String value) {
print('name:$value');
});
}
2秒后打印日志:
flutter: name:老孟
Future.then.catchError
有这样一个Future方法:延迟1秒将字符串转换为int类型,代码如下:
Future<int> parse(String value) {
return Future.delayed(Duration(seconds: 1), () {
return int.parse(value);
});
}
调用此方法:
parse("2").then((int value) {
print('value:$value');
});
此时可以正确转换,输出日志:
flutter: value:2
如果入参为非数字,则会出现转换异常,代码如下:
parse("2a").then((int value) {
print('value:$value');
});
运行,抛出异常:
此时,需要捕获异常并做处理,代码如下:
parse("2a").then((int value) {
print('value:$value');
}).catchError((error){
print('error:$error');
});
输出日志:
flutter: error:FormatException: Invalid radix-10 number (at character 1)
2a
^
Future 的异常不能使用 try..catch 捕获。
Future 可以返回任意类型的值,也可以不返回值,
Future<void> futureVoid() {
return Future.delayed(Duration(seconds: 1), () {
//do something
});
}
Future.delayed
延迟处理,上面已经多次使用,延迟1秒执行:
Future.delayed(Duration(seconds: 1), () {
//do something
});
Future.value
创建一个带返回值的 Future :
Future<String> futureValue() {
return Future.value('老孟');
}
Future.any
返回[futures]中要完成的第一个Future的结果,返回的第一个结果表示已完成,其他Future结果被抛弃。如果[futures]为空,或者没有一个Future完成,那么Future永远不会完成。
Future<String> futureAny() {
return Future.any([
Future.delayed(Duration(seconds: 1),()=> '1'),
Future.delayed(Duration(seconds: 2),()=> '2'),
Future.delayed(Duration(seconds: 3),()=> '3'),
]);
}
输出日志:
flutter: value:1
Future.microtask
Flutter 的 main isolate 中有2个队列:Event Queue 和 Microtask Queue ,这两个 Queue 区别是 Microtask Queue执行的优先级比Event Queue高。
Future.microtask 是向Microtask Queue添加任务,而其他Future 方法是向Event Queue中添加任务。
Future<String> futureMicrotask() {
return Future.microtask(()=>'老孟');
}
Future.sync
表示Future中代码是同步执行的。
Future<void> futureSync() {
return Future.sync(()=>print('Future.sync'));
}
调用:
void _incrementCounter() {
print('Future.sync begin');
futureSync();
print('Future.sync end');
}
打印日志:
flutter: Future.sync begin
flutter: Future.sync
flutter: Future.sync end
Future.error
返回异常,可以通过catchError捕获。
Future<void> futureSync() {
return Future.sync(() => print('Future.sync'));
}
调用:
futureError().catchError((error) {
print('$error');
});
输出日志:
flutter: this is error
Future.doWhile
重复执行操作,直到返回 false。
Future<void> futureDoWhile() {
var i = 0;
return Future.doWhile(() {
print('i:$i');
return Future.value(i++ < 10);
});
}
日志输出:
flutter: i:0
flutter: i:1
flutter: i:2
flutter: i:3
flutter: i:4
flutter: i:5
flutter: i:6
flutter: i:7
flutter: i:8
flutter: i:9
flutter: i:10
Future.forEach
遍历完所有的值或者抛出异常才变为完成状态。
Future<void> futureForEach() {
return Future.forEach([1,2,3,5],(value){
print('value:$value');
});
}
日志输出:
flutter: value:1
flutter: value:2
flutter: value:3
flutter: value:5
async, await
async 和 await 关键字允许我们像写同步代码一样写异步代码,有如下异步函数:
Future<int> parse(String value) {
return Future.delayed(Duration(seconds: 1), () {
return int.parse(value);
});
}
可以使用如下方法获取结果:
void _incrementCounter() {
parse('2').then((value) => print('value:$value'));
}
也可以使用如下方法:
void _incrementCounter() async {
var result = await parse('2');
print('result:$result');
}
日志输出:
flutter: result:2
使用async 和 await 可读性更强。
使用 async 修饰的方法返回 Future,是异步方法。
Future<int> toInt(String value) async {
return int.parse(value);
}
async 和 await 的异常捕获需要使用try..catcch
void _incrementCounter() async {
try{
await parse('1');
}catch(e){
}
}
总结
async 和 await 关键字可以认为是 Future 的语法糖。
async 和 await 关键字可以有效的解决 Future.then 嵌套问题
void _incrementCounter() {
fun1().then((value) {
fun2().then((value) {
fun3().then((value) {});
});
});
}
Future<String> fun1() {
return Future.value('a');
}
Future<String> fun2() {
return Future.value('b');
}
Future<String> fun3() {
return Future.value('c');
}这种地狱嵌套可读性非常差,使用async 和 await 写法:
void _incrementCounter() async {
var result1 = await fun1();
var result2 = await fun2();
var result3 = await fun3();
}Future.then 可以使用链式调用
void _incrementCounter() async {
fun1()
.then((value) {})
.then((value){});
}