Flutter 异步编程:Futures
Flutter异步编程-Futures
本文大纲
1. 什么是Future?
2. 如何创建Future实例?
3. 一个令人迷惑的例子
4. 参考和更多阅读
1. 什么是Future?
本文小菜带大家认识和理解下 Futures 的用法以及原理。
经常听说 future,或者从其他语言见到类似的说法如 javascript 的 Promise。那么究竟什么是 future?
A future (lower case “f”) is an instance of the Future (capitalized “F”) class. A future represents the result of an asynchronous operation, and can have two states: uncompleted or completed.
https://dart.dev/codelabs/async-await
future 是 Future 类的实例,表示一个 异步操作的结果
,这个结果会有两种状态:
未完成和已完成
。
我们可以将future理解成一个未知的盒子,盒子里包裹着一个value值,类型为T,这个盒子会被投递到你的手中,盒子没到达你的手中时处于未完成状态,到达你的手中后,打开盒子,可能是成功返回的data数据(也包括没有返回值void),也可能是失败返回的error数据。
有几个术语需要理解下:
– 同步操作
:同步操作会阻塞后面其他的操作直至完成
– 同步函数
:同步函数内部一定都是同步操作,顺序完成
– 异步操作
:异步操作允许在其完成之前进行其他操作(执行其他代码)
– 异步函数
:异步函数内部至少有一个异步操作,允许有同步操作和同步函数存在。
1.1 什么是未完成?
当我们调用一个异步函数,异步函数会返回一个未完成的 future 实例。这个 future 会等待异步函数的操作完成或者失败抛出错误异常。
1.2 什么是已完成?
当异步操作成功,future便会以操作的结果结束,否则以错误结束。
我们常常见到异步函数返回值类型为 Future
所以将已完成再拆分,future可以认为有三种状态:
– Uncompleted
未完成 (类似Promise的pending)
– Completed with data
成功,返回data数据(类似Promise的fulfilled)
– Complted with error
失败,返回error数据(类似Promise的rejected)
2. 如何创建Future实例?
1. 一些已有的封装api
一些常用的api或者三方库已经封装好了,直接使用,比如
final future1 = http.get("httts://www.google.com");
final future2 = SharedPreferences.getInstance();
···
2. Future类的工厂方法
A) factory Future(FutureOr
/// factory Future(FutureOr<T> computation())
/// 创建一个包含调用computation结果的future。
final myFuture = Future(() {
return "HelloFlutter!";
});
B) factory Future.microtask(FutureOr
/// factory Future.microtask(FutureOr<T> computation())
/// 创建一个future,scheduleMicrotask将computation放到微任务调用处理,然后返回结果。
final myFuture = Future.microtask(() {
return "HelloFlutter!";
});
C) factory Future.sync(FutureOr
/// factory Future.sync(FutureOr<T> computation())
/// 创建一个future,包含立即调用computation的结果。
/// 如果结果类型为Future<T>,则直接返回
/// 如果不为Future<T>,则会创建并返回一个已经完成的future,值value为result
final myFuture = Future.sync(() {
return "HelloFlutter";
});
D) factory Future.value([FutureOr
value])
/// factory Future.value([FutureOr<T> value])
/// 创建一个值为value的成功态future。
final myFuture = Future.value("HelloFlutter!");
E) factory Future.error(Object error, [StackTrace stackTrace])
/// factory Future.error(Object error, [StackTrace stackTrace])
/// 创建一个error的失败态future,可选参数为堆栈信息
final myFuture = Future.error(Exception());
F) factory Future.delayed(Duration duration, [FutureOr
/// factory Future.delayed(Duration duration, [FutureOr<T> computation()])
/// 创建一个延时执行computation的future
final myFuture = Future.delayed(Duration(seconds: 2), () => "HelloFlutter!");
3. 一个令人迷惑的例子
// main.dart void main() { runFuturesDemo(); } // futures_demo.dart void runFuturesDemo() async { print("runFuturesDemo start...");
// future1 ------------------------------------ Future future1 = new Future(() => null); future1.then((_) { print("future1 then 1"); }).catchError((e) { print("future1 catchError"); }).whenComplete(() { print("future1 whenComplete"); });
// future2 ------------------------------------ Future future2 = Future(() { print("future2 init"); });
future2.then((_) { print("future2 then"); future1.then((_) { print("future1 then3"); }); }).catchError((e) { print("future2 catchError"); }).whenComplete(() { print("future2 whenComplete"); });
future1.then((_) { print("future1 then2"); });
// future3 ------------------------------------ Future future3 = Future.microtask(() { print("future3 init"); });
// future4 ------------------------------------ Future future4 = Future.sync(() { print("future4 init"); });
// future5 ------------------------------------ Future future5 = Future(() { print("future5 init"); });
// future6 ------------------------------------ Future future6 = Future.delayed(Duration(seconds: 3), () { print("future6 init"); });
print("runFuturesDemo end..."); }
聪明的你,思考下,打印顺序是什么呢?
深刻理解 futures 的机制,才能在复杂的业务场景中或者构建基础架构时游刃有余,立于不败之地。
下面是正确的输出,符合你的预期吗?如果不符合的话,是哪里理解不对呢?
demo地址:https://github.com/dabing1022/flutter_async_programming
事实a)执行 main 函数,在 main 里面会往 microtask queue 和 event queue 中添加任务和事件, 包括注册一些回调,结束后,开启event loop
事实
b)事件循环中 microtask queue 优先级 > event queue 优先级
事实
c)从上面工厂方法 Future.sync
源码截图中可以看到,先同步执行computation(于是打印”future4 init”),根据 computation() 返回值视情况进行 Future 封箱(如果 compuation() 返回值为 Future
事实
d)为什么 7 排在 8 前面?
我们看源码 then 的注释:
Futurethen (FutureOr onValue(T value), {Function onError});
* Register callbacks to be called when this future completes. * * When this future completes with a value, * the [onValue] callback will be called with that value. * If this future is already completed, the callback will not be called * immediately, but will be scheduled in a later microtask.
因为 future1 已经 completed 了,所以 future1 在7这个位置再次用 then 注册的 callback 回调会被放在 microtask 中执行。microtask的优先级高,所以 7 会在 8 前面打印。
事实e)为什么 11 排在 9 后面而不是 7 后面?
future2 在 event queue 事件队列中排在了 future1 后面,future2 init 执行完毕后,交给 then 的回调处理,此时位置 11 处,即 future1 使用 then 注册的 callback 在 future2 的 then 的 callback 里面,所以会处在 9 后面而不是 7 后面。
flutter: runFuturesDemo start... flutter: future4 init flutter: runFuturesDemo end... flutter: future3 init flutter: future1 then 1 flutter: future1 whenComplete flutter: future1 then2 flutter: future2 init flutter: future2 then flutter: future2 whenComplete flutter: future1 then3 flutter: future5 init flutter: future6 init
4. 如何自定义Future?
无论是在做基础架构设计还是业务设计中,常常会需要自定义 Future。我们如何自定义 Future,其实可以参考源码的写法。
关键字 Completer
!
Completer是一种可以生成以value或者error为结果的Future对象的一种方式。
大部分时候,我们创建future,可以使用上面提到的工厂方法来创建,比如
new Future(() { doSomething(); return result; });
如果future表示一个异步操作序列的结果,那么可以使用 Future.then 等来链式操作。比如
Future doStuff(){
return someAsyncOperation().then((result) {
return someOtherAsyncOperation(result);
});
}
但是如果我们想自定义一个 Future,比如我们需要将基于 callback 回调的一个 api 转化为基于 future 设计的流程,如何做呢?
这里我举个例子,我们在数据库里根据 id 查询名字:
Future queryName(int id) {
// 创建一个completer
var completer = new Completer();
// 查询数据库,然后根据成功或者失败执行相应的callback回调,这个过程是异步的
database.query("select name from user where id = $id", (results) {
completer.complete(results);
}, (error) {
completer.completeError(error);
});
// return 在query结果出来之前就会被执行
return completer.future;
}
后面我们如何使用 queryName 呢?常见两种方式来 “打开箱子”
:
await 或者 then
。
1)await方式
void runFuturesDemo2() async {
try {
final name = await queryName(100);
print("id 100 user name is $name");
} catch (e) {
print(e.toString());
} finally {
print("finally finished.");
}
}
2)then方式
void runFuturesDemo2() {
queryName(100).then((name) {
print("id 100 user name is $name");
}, onError: (e) {
print(e.toString());
}).whenComplete(() {
print("finally finished.");
});
}
类似自定义 Promise 我们看下:
Promise使用 resolve 和 reject 来执行成功或者异常,data 或者 error 在 then 的注册回调里面被使用。
自定义 Future 如下:
推荐读者阅读 future.dart
和 future_impl.dart
源码。
5. 参考和更多阅读
– https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
– https://dart.dev/codelabs/async-await
– 阅读
future.dart 和
future_impl.dart 源码