昨天介绍了在Dart中非同步的基本概念,今天就要来讲到如何简单的控制非同步操作。
Future
可以想像成一个盒子一样,它将 「一个值装起来直到未来某个时间点才会打开」
直接看code,我们宣告了一个function他会回传一个 Future<String>
,同时我也会看到 Future
最基本的 constructor Future(FutureOr<T> computation())
所以这边我们先传入一个会回传String的 Function
Future<String> fetchData() => Future(
() => 'Data',
);
然後到main里使用:
final data = fetchData();
print(data);
会发现输出不是 Data
而是 Instance of 'Future<String>'
为什麽呢?就像前面所说的Future
可以想像成一个盒子一样,所以我们必须将它打开才能取出它的值。
而打开这个盒子的其中一种方法就是用 then
fetchData().then((value) => print(value));
// Data
.then
会回传一个callback 然後我们就可以用 (value) => print(value)
这种形式来使用它,那如果我的非同步是有一连串的顺序呢?
假设我想要非同步的取得一个资料後,再经过三秒後才输出的话
一样先定义两个回传 Future<String>
的 function
Future<String> outputAfter3s(String data) => Future.delayed(
Duration(seconds: 3),
() => data,
);
Future<String> fetchData() => Future(
() => 'data',
);
在使用上就直接插入一个 .then
就是这麽简单
fetchData()
.then(
(value) => outputAfter3s(value),
)
.then((value) => print(value))
整个流程大概如下:
outputAfter3s
回传一个 Future
後,一样是一个FutureOr<T> computation()
所以可以继续往下接.then
,这个FutureOr
意思是可能是 T
或者 Future<T>
。
所以其实也可以直接传一个value下去
fetchData()
.then(
(value) => outputAfter3s(value),
)
.then((value) => value)
.then((value) => print(value.length))
// 4
Future
另外一个好处是可以让我们更方便的catch error
Future throwError() => Future(
() => throw 'error 123456',
);
// 省略其他code ...
fetchData()
.then((value) => throwError())
.then(
(value) => outputAfter3s(value),
)
.then((value) => value)
.then((value) => print(value.length))
.catchError(
(err) => print('catch error: $err'),
);
我们这边先直接宣告一个一定会throw error的function,当然在实务上常见的可能会是http client发生一些错误才会throw error。
然後我们利用 catchError
来做错误处理,使用方式也很简单,它一样会回传一个 callback 里面可以取得这次非同步中throw error。
所以会有以下输出
catch error: error 123456
如果我有一些操作是想要整个Future chain 都结束後且 「无论失败或成功」 都要执行的话那我该如何写?
fetchData()
.then((value) => throwError())
.then(
(value) => outputAfter3s(value),
)
.then((value) => value)
.then((value) => print(value.length))
.catchError(
(err) => print('catch error: $err'),
)
.whenComplete(() => print('completed'));
可以使用 whenComplete
这个api 来达成而且他是 「无论失败或成功」 只要这个 Future
有了结果回传都会执行。
所以输出会是这样
catch error: error 123456
completed
如果没有throw error:
4
completed
所以我们现在可以得知future有三种状态 「成功」、「失败」、「未完成」 ,但为什麽没有讲解到 「未完成」 (pending)时候的控制呢?主要是因为这件事情有了UI才会比较需要呈现。所以等之後进入到flutter的文章时再来慢慢介绍要如何实作分别呈现 「成功」、「失败」、「未完成」 这三种UI。
这次讲了算是相当常见的 Future
,但其实我们在绝大多数的场景下很少自己建立Future
,大多数时候都是第三方服务会回传Future
来让我们做控制像是http request 之类的。
但你可能会想问难道我只能从 then
里面才能将值取出来吗?如果我有将Future
里的值取出来放到另外一个变数该如何做?其实如果有state存在的话,是可以在Future
chain里去将state改变。但大多数的做法应该都会是利用 async/await
来达成这件事情,就等到明天再来好好说明async/await
了。
今天的程序码:
https://github.com/zxc469469/dart-playground/tree/Day09/future
参考资料
https://www.youtube.com/watch?v=OTS-ap9_aXc
<<: 07 - Metrics - 观察系统的健康指标 (1/6) - Metrics 与 Metricbeat 的基本介绍
>>: Day08:08 - User服务(3) - 後端 - JWT token、修改个人资料
最短路径演算法 最短路径是在赋予edges权重的「加权图形」里,指定「起点」和「终点」,求出起点到终...
有了总体经济的图表之後,接下来就要来制作各国股市的资讯站,笔者最常看的就是台股的资讯,其次则是美股、...
「三是一个质数,是一个特别的存在。」 「三角形是最坚固的形状,最强韧的组合。」 三个人的团队,是最适...
WirelessKeyView 今天来认识 WirelessKeyView这个酷东西! (还有其他密...
Veeam Backup专业级备份软件从入门到实战_01 课程大纲: 1.Veeam公司介绍 2.V...