Future
对象来执行异步操做await
关键字来挂起执行知道一个Future操做完成then()
方法catchError()
方法dart是一个单线程的编程语言,若是编写了任何阻塞执行线程的代码(例如耗时计算或者I/O),程序就会被阻塞。异步操做可让你在等待一个操做完成的同时完成其余工做。Dart使用Future
对象来进行异步操做。html
先来看一个会致使阻塞的程序代码:web
// Synchronous code
void printDailyNewsDigest() {
var newsDigest = gatherNewsReports(); // Can take a while.
print(newsDigest);
}
main() {
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
复制代码
程序会收集当天的新闻而且打印出来(耗时操做),而后打印一些用户感兴趣的其余信息。编程
<gathered news goes here>
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny. Baseball score: Red Sox 10, Yankees 0 复制代码
这段代码是有问题的,当printDailyNewsDigest()
方法作耗时操做阻塞,剩下的其余代码不管多长时间都只有等到printDailyNewsDigest()
返回结果以后才能继续执行。api
为了帮助保持应用程序的响应,Dart库的做者在定义可能作耗时工做的函数时用了异步模型。这些函数的返回值是一个future。bash
一个future是一个Future的泛型Future<T>
对象,表明了一个异步操做产生的T类型的结果。若是结果的值不可用,future的类型会是Future<void>
,当返回一个future的函数被调用了,将会发生以下两件事: 1.这个函数加入待完成的队列而且返回一个未完成的Future
对象。 2.接着,当这个操做结束了,Future
对象返回一个值或者错误。异步
编写返回一个future的代码时,有两面两个可选方法:async
Future
APIasync
和 await
关键字是Dart语言异步支持的一部分。容许你不使用Future api像编写同步代码同样编写异步代码。一个异步函数的函数体前面要生命async
关键字,await
关键字仅在异步函数里生效。编程语言
下面的代码就是一个使用了Future api的例子。ide
import 'dart:async';
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then(print);
// You don't *have* to return the future here.
// But if you don't, callers can't await it.
}
main() {
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
printWinningLotteryNumbers() {
print('Winning lotto numbers: [23, 63, 87, 26, 2]');
}
printWeatherForecast() {
print("Tomorrow's forecast: 70F, sunny.");
}
printBaseballScore() {
print('Baseball score: Red Sox 10, Yankees 0');
}
const news = '<gathered news goes here>';
const oneSecond = Duration(seconds: 1);
// Imagine that this function is more complex and slow. :)
Future<String> gatherNewsReports() =>
Future.delayed(oneSecond, () => news);
复制代码
在main()
方法里面printDailyNewsDigest()
是一个被调用的,可是由于等待了一秒延迟执行,因此在最后才被打印出来。这个程序的执行顺序以下:函数
1.程序开始执行
2.main方法调用printDailyNewsDigest()
,可是不会当即返回,会调用gatherNewsReports()
3.gatherNewsReports()
开始收集新闻同时返回一个Future
。
4.printDailyNewsDigest()
使用then()
指定一个Future的响应结果,调用then()
返回一个新完成的Future结果做为他的回调。
5.剩下的print方法是同步的会依次执行。
6.当全部的新闻都被收集到了,带有新闻信息的Future被gatherNewsReports()
返回。
7.then()
方法执行,将future返回的String做为参数传递给print
打印。
future.then(print)
等同于future.then((newsDigest) => print(newsDigest))
因此printDailyNewsDigest()
还能够写成:
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then((newsDigest) {
print(newsDigest);
// Do something else...
});
}
复制代码
newsDigest是gatherNewsReports()
返回的结果。
即时这个Future的类型是Future<void>
,也须要传递一个参数给then()
的回调,直接用下划线_
表示。
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then((_) {
// Code that doesn't use the `_` parameter...
print('All reports printed.');
});
}
复制代码
在Future api里,能够使用catchError()
捕获错误:
Future<void> printDailyNewsDigest() =>
gatherNewsReports().then(print).catchError(handleError);
复制代码
若是请求不到新闻而且失败了,上面的代码将会执行:
1.gatherNewsReports()
完成返回的future携带了error
2.then()
方法中的print不会被执行
3.catchError()
捕获处处理错误,future被catchError()
正常完成并返回,错误不会继续传递下去。
更多细节阅读 Futures and Error Handling
有三个函数,expensiveA()
、 expensiveB()
和 expensiveC()
, 它们都返回Future对象。你能够顺序调用它们(one by one),或者也能够同时调用三个函数而且当全部结果都返回时再作处理。Future api支持以上的操做。
按顺序使用then()调用每一个方法
expensiveA()
.then((aValue) => expensiveB())
.then((bValue) => expensiveC())
.then((cValue) => doSomethingWith(cValue));
复制代码
这是个嵌套调用,上一个函数的返回结果做为下一个函数的参数。
若是好几个函数的执行顺序可有可无,能够使用Future.wait()
。
Future.wait([expensiveA(), expensiveB(), expensiveC()])
.then((List responses) => chooseBestResponse(responses, moreInfo))
.catchError(handleError);
复制代码
当传递一个future列表给Future.wait()
时,它会当即返回一个Future,可是直到列表里的future都完成的时候,这个Future才会完成,他会返回一个列表里面是每个future产生的结果数据。
若是任何一个调用的函数产生了错误,都会被catchError()
捕获到去处理错误。