flutter-Future(async、await)
前言
很多人感觉 flutter
中的 Future
和 JavaScript
中的 Promise
一样,但是系统介绍却只有一个简单的 async、await
使用,实际上他们原理是一样的,使用方法也很相似
async、await
实际上就是对 Future
或者 Proimise
的一种使用罢了,只不过看起来没有那么明显
Future
Future 与 async、await
我们定义一个方法,来对比一下异步函数的定义,会发现他们两个就是一个东西
//定义两个方法,一个带返回值,一个不带
Future<int> getUserInfo() async {
print(789);
return 1;
}
//下面几个函数一样
//Future getUserInfo2() async
//Future<dynamic> getUserInfo2() async
getUserInfo2() async {
print(123);
return 2;
}
//Future<void>跟下面的一样
void getUserInfo3() async {
}
//测试方法
testGetUserInfo() {
final user1 = getUserInfo();
print(user1);
final user2 = getUserInfo2();
print(user2);
}
testGetUserInfo2() async {
final user1 = await getUserInfo();
print(user1);
final user2 = await getUserInfo2();
print(user2);
}
分别代码执行两个测试代码后,返回了下面的结果
//执行testGetUserInfo
789
Instance of 'Future<int>'
123
Instance of 'Future<dynamic>'
//执行testGetUserInfo2
789
1
123
2
通过测试结果更加能表明,两个函数默认返回的是一个 Future对象
,其中无返回值的函数,返回的是一个泛型为任意类型 dynamic
的 Future对象
如果采用了 await
之后,此函数会被阻塞执行,直到await
里面的执行完毕后,返回结果,才继续往后执行
前面也有提到过,await
的函数阻塞
后,被放到一个队列
中,延迟执行
了,毕竟 flutter
为单线程模式,Future
只是在模拟多线程的操作而已
异步函数的使用
上面了解了 Future
和 async
他们的关系之后,这里进一步了解,编写一个异步函数
看了下面代码,会发现,实际上 async
就是封装的一个 Future
函数罢了,返回值为 Future
的 同步函数,因此需要 await
才能达到异步效果(不使用await
,就都是同步执行
),相信更了解其使用了
//Future其实和js中的 Promise 相似
Future delay1Second() async {
print("我要沉睡");
sleep(Duration(seconds: 1));
print("沉睡完毕");
}
//这个代码实际和上面一样,上面的只是系统自动包装了一个Future而已
Future delay1SecondReplace() {
return Future(() {
print("我要沉睡备用");
sleep(Duration(seconds: 1));
print("沉睡完毕备用");
});
}
上面的测试结果就不列出来了,和预料一模一样
Future进阶使用
前面提到了 Promise
, Future
也能和他一样使用
对于返回类型不是 Future
的类型,或者需要加工处理一些异步函数的结果时,难免碰到单纯使用 async、await
不太好使的问题,下面就编写一个案例,来演示如何使用
下面有一个方法,是以闭包
的方式,异步回调
一个结果
//我调用了一个三方,以闭包的方式,异步回调一个结果
threeMethod(Function(int? result) completed) {
Future.delayed(Duration(seconds: 2), () {
print("我是一个三方的耗时算法,大约执行2s之后才会有相应");
//取一个最大为10的随机int整数数
if (Random().nextInt(10) % 10 > 4) {
completed(5);
}else {
completed(null);
}
});
}
写过 javascript
的人会很激动,这个我会,一个 Promise
+ resolve、reject
就解决了,例如下面
//Promise版本
workThreeMethod() {
return Promise((resolve, reject) => {
threeMethod((res) {
//对方执行完毕后的回调,返回null就是计算出错了,这里给外面一个error
if (res == null) {
//也可以不返回error,只有completed,那样就是外面不用catch了
reject(new Error("计算出错了,返回一个错误,需要外面catch一下"));
}else {
resolve(5);
}
})
});
}
可是,Future
,中没有 resolve、reject
怎么办?
系统提供了 Completer
类,如下所示,会发现,除了多引出一个对象,太相似了
workThreeMethod() {
//如果不想往外传值,泛型就改成void,否则使用指定类型,或者不填(不填默认为dynamic)
final completer = Completer<int>();
threeMethod((res) {
//对方执行完毕后的回调,返回null就是计算出错了,这里给外面一个error
if (res == null) {
//也可以不返回error,只有completed,那样就是外面不用catch了
//await时会报错,报crash,外面需要.catch
completer.completeError("计算出错了,返回一个错误,需要外面catch一下");
}else {
//回到结果,await的就是这里回调的结果
completer.complete(5);
}
});
return completer.future;//最后返回一个future
}
下面就是正确的调用场景,对于有错误的
//有回调错误的一般这么写
testWorkThreeMethod() {
workThreeMethod().then((res) {
print('res:${res}');
}).catchError((err) {
print('err:' + err);
});
}
//也可以这么写,这样函数本来的错误,也会到这里
testWorkThreeMethod2() async {
try {
final res = await workThreeMethod();
print(res);
}catch(err) {
print(err);
}
}
如下所示,可以看到两个执行结果一样
我是一个三方的耗时算法,大约执行2s之后才会有相应
err:计算出错了,返回一个错误,需要外面catch一下
我是一个三方的耗时算法,大约执行2s之后才会有相应
计算出错了,返回一个错误,需要外面catch一下
ps
:第二个除了捕获到自己的completeError
,还能捕获到自己代码的error
最后
Future
原理上和 Promise
一样,其他语言如果也有类似的,那么可以尝试一下是否原理一致,类似的东西可以串起来
另外 Promise
中的 All
,Future
中也有哈
例如: Future
中的 any
,参数为 Future数组
,返回也是一个 Future
,结果为数组类型
看完,是不是感觉很简单呢,快来试试吧
转载自:https://juejin.cn/post/7074571685734645768