Flutter 异步编程:Futures

栏目: IT技术 · 发布时间: 4年前

内容简介:Flutter异步编程-Futures

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数据。

Flutter 异步编程:Futures

有几个术语需要理解下:

- 同步操作 :同步操作会阻塞后面其他的操作直至完成

- 同步函数 :同步函数内部一定都是同步操作,顺序完成

- 异步操作 :异步操作允许在其完成之前进行其他操作(执行其他代码)

- 异步函数 :异步函数内部至少有一个异步操作,允许有同步操作和同步函数存在。

1.1 什么是未完成?

当我们调用一个异步函数,异步函数会返回一个未完成的 future 实例。这个 future 会等待异步函数的操作完成或者失败抛出错误异常。

1.2 什么是已完成?

当异步操作成功,future便会以操作的结果结束,否则以错误结束。

我们常常见到异步函数返回值类型为 Future<T>。Future<T>表示将来某个时间点异步操作执行成功或者失败的结果,结果类型为T。如果无返回结果,使用Future<void>表示。

所以将已完成再拆分,future可以认为有三种状态:

- Uncompleted 未完成 (类似Promise的pending)

- Completed with data 成功,返回data数据(类似Promise的fulfilled)

- Complted with error 失败,返回error数据(类似Promise的rejected)

2. 如何创建Future实例?

1. 一些已有的封装api

一些常用的api或者三方库已经封装好了,直接使用,比如

<span>final future1 = http.get(&quot;httts://www.google.com&quot;);</span>

<span>final future2 = SharedPreferences.getInstance();</span>

<span>&middot;&middot;&middot;</span>

2. Future类的工厂方法

Flutter 异步编程:Futures

A)  factory Future(FutureOr<T> computation()) 

<span>/// factory Future(FutureOr&lt;T&gt; computation()) </span>

<span>/// 创建一个包含调用computation结果的future。</span>

<span>final myFuture = Future(() {</span>

<span> return &quot;HelloFlutter!&quot;;</span>

<span>});</span>

B)  factory Future.microtask(FutureOr<T> computation())

<span>/// factory Future.microtask(FutureOr&lt;T&gt; computation())</span>

<span>/// 创建一个future,scheduleMicrotask将computation放到微任务调用处理,然后返回结果。</span>

<span>final myFuture = Future.microtask(() {</span>

<span> return &quot;HelloFlutter!&quot;;</span>

<span>});</span>

C)  factory Future.sync(FutureOr<T> computation())  

Flutter 异步编程:Futures

<span>/// factory Future.sync(FutureOr&lt;T&gt; computation()) </span>

<span>/// 创建一个future,包含立即调用computation的结果。</span>

<span>/// 如果结果类型为Future&lt;T&gt;,则直接返回</span>

<span>/// 如果不为Future&lt;T&gt;,则会创建并返回一个已经完成的future,值value为result</span>

<span>final myFuture = Future.sync(() {</span>

<span> return &quot;HelloFlutter&quot;;</span>

<span>});</span>

D)   factory Future.value([FutureOr <T>  value])

<span>/// factory Future.value([FutureOr&lt;T&gt; value])</span>

<span>/// 创建一个值为value的成功态future。</span>

<span>final myFuture = Future.value(&quot;HelloFlutter!&quot;);</span>

E)  factory Future.error(Object error, [StackTrace stackTrace])

<span>/// factory Future.error(Object error, [StackTrace stackTrace])</span>

<span>/// 创建一个error的失败态future,可选参数为堆栈信息</span>

<span>final myFuture = Future.error(Exception());</span>

F)  factory Future.delayed(Duration duration, [FutureOr<T> computation()])

<span>/// factory Future.delayed(Duration duration, [FutureOr&lt;T&gt; computation()])</span>

<span>/// 创建一个延时执行computation的future</span>

<span>final myFuture = Future.delayed(Duration(seconds: 2), () =&gt; &quot;HelloFlutter!&quot;);</span>

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 的机制,才能在复杂的业务场景中或者构建基础架构时游刃有余,立于不败之地。

下面是正确的输出,符合你的预期吗?如果不符合的话,是哪里理解不对呢?

Flutter 异步编程: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<T>,直接返回,如果不是,则使用 _Future.value 将结果封箱)。

事实 d)为什么 7 排在 8 前面?

我们看源码 then 的注释:

Future<R> then<R>(FutureOr<R> 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 等来链式操作。比如

<span> Future doStuff(){</span>

<span> return someAsyncOperation().then((result) {</span>

<span> return someOtherAsyncOperation(result);</span>

<span> });</span>

<span> }</span>

但是如果我们想自定义一个 Future,比如我们需要将基于 callback 回调的一个 api 转化为基于 future 设计的流程,如何做呢?

这里我举个例子,我们在数据库里根据 id 查询名字:

<span>Future queryName(int id) {</span>

<span> // 创建一个completer</span>

<span> var completer = new Completer();</span>

<span> </span>

<span> // 查询数据库,然后根据成功或者失败执行相应的callback回调,这个过程是异步的</span>

<span> database.query(&quot;select name from user where id = $id&quot;, (results) {</span>

<span> completer.complete(results);</span>

<span> }, (error) {</span>

<span> completer.completeError(error);</span>

<span> });</span>

<span> </span>

<span> // return 在query结果出来之前就会被执行</span>

<span> return completer.future;</span>

<span>}</span>

后面我们如何使用 queryName 呢?常见两种方式来 "打开箱子" await 或者 then

1)await方式

<span>void runFuturesDemo2() async {</span>

<span> try {</span>

<span> final name = await queryName(100); </span>

<span> print(&quot;id 100 user name is $name&quot;);</span>

<span> } catch (e) {</span>

<span> print(e.toString());</span>

<span> } finally {</span>

<span> print(&quot;finally finished.&quot;);</span>

<span> }</span>

<span>}</span>

2)then方式

<span>void runFuturesDemo2() {</span>

<span> queryName(100).then((name) {</span>

<span> print(&quot;id 100 user name is $name&quot;);</span>

<span> }, onError: (e) {</span>

<span> print(e.toString());</span>

<span> }).whenComplete(() {</span>

<span> print(&quot;finally finished.&quot;);</span>

<span> });</span>

<span>}</span>

类似自定义 Promise 我们看下:

Flutter 异步编程:Futures

Promise使用 resolve 和 reject 来执行成功或者异常,data 或者 error 在 then 的注册回调里面被使用。

自定义 Future 如下:

Flutter 异步编程:Futures

推荐读者阅读  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  源码


以上所述就是小编给大家介绍的《Flutter 异步编程:Futures》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

海星模式

海星模式

奥瑞·布莱福曼、罗德·贝克斯特朗 / 李江波 / 中信出版社 / 2008-1 / 36.00元

如果砍掉一只蜘蛛的脑袋,毫无疑问它会死掉;但是砍掉海星的一条手臂,它却会长出一只新的来,就连那只砍掉的手臂也会长成一个完整的新海星。传统意义上自上而下的组织模式就像蜘蛛,然而现在正在改变着企业和世界面貌的却是海星型组织。 维基百科、craigslist和Skype的成功下面隐藏着什么样的力量?易趣公司和通用电气公司与废奴和女权运动又有什么共同之处?到底是什么样的重大选择使得通用汽车公司与丰田......一起来看看 《海星模式》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具