Dart API 學(xué)習(xí)記錄(一) http://www.reibang.com/p/388d986c0f48
Dart API 學(xué)習(xí)記錄(二)
dart:async
庫(kù)
dart:async
庫(kù)是Dart 語(yǔ)言支持異步編程的基礎(chǔ)友浸。
庫(kù)中提供了Future 類(lèi)和Stream 類(lèi)灭抑。這兩個(gè)類(lèi)是理解Dart 語(yǔ)言異步機(jī)制的基礎(chǔ)镐躲。
在使用前async 庫(kù)的功能前需要在代碼中添加如下語(yǔ)句:
import 'dart:async'
Future 類(lèi)
Future 對(duì)象返回值表明當(dāng)前時(shí)刻的計(jì)算結(jié)果可能還不可用十拣。
Future 實(shí)例會(huì)在計(jì)算結(jié)束后再返回結(jié)果橙依,而不是現(xiàn)在立即返回眨八。
Future 通常用來(lái)操作冗長(zhǎng)的計(jì)算钞它,比如大規(guī)模的I/O 操作或與用戶進(jìn)行交互坡垫。
下面的例子將返回一個(gè)Future:
import 'dart:io';
void bindServer(){
HttpServer.bind('127.0.0.1', 4444)
.then((server) => print('${server.isBroadcast}'))
.catchError(print);
}
void main(){
bindServer();
}
在例子中Future.then
注冊(cè)了一個(gè)回調(diào)函數(shù)彭沼,當(dāng)bind() 方法執(zhí)行完成后開(kāi)始運(yùn)行缔逛。回調(diào)函數(shù)的功能是: 當(dāng)bind()執(zhí)行成功后會(huì)返回一個(gè)HttpServer 的對(duì)象,在回調(diào)函數(shù)中會(huì)返回該HttpServer的一個(gè)熟悉值褐奴。
Stream 類(lèi)
一個(gè)Stream 對(duì)象提供了一個(gè)異步數(shù)據(jù)的隊(duì)列按脚。在這個(gè)隊(duì)列中可能包含事件(鼠標(biāo)點(diǎn)擊),大數(shù)據(jù)塊.
利用Stream 方法來(lái)讀取文件的例子:
import 'dart:async';
import 'dart:io';
import 'dart:convert';
void readFile(f){
Stream<List<int>> stream = new File(f).openRead();
stream.transform(UTF8.decoder).listen(print);
}
void main(){
String filename = "/opt/program/Dart/dart-code/test_data/temp.py";
readFile(filename);
Asynchronous Programming: Futures
以下的內(nèi)容來(lái)源于下列地址:
https://www.dartlang.org/tutorials/language/futures
要點(diǎn)總結(jié)
- Dart 語(yǔ)言是單線程的敦冬。
- 同步的代碼可能導(dǎo)致代碼阻塞辅搬。
- 可以使用Future 方法來(lái)執(zhí)行異步操作。
- 在異步方法里使用
await()
來(lái)暫停代碼執(zhí)行脖旱,直到Future 執(zhí)行完成堪遂。 - 也可使用Future 的
then()
方法來(lái)實(shí)現(xiàn)上面的目的。 - 在異步方法里使用
try...catch...
來(lái)獲取異常萌庆。 - 也可是使用Future 的
catchError()
方法來(lái)實(shí)現(xiàn)上面的目的溶褪。 - 可以就多個(gè)異步的方法鏈接起來(lái)順序執(zhí)行。
簡(jiǎn)介
可能導(dǎo)致代碼阻塞的例子:
void printDailyNewsDigest(){
// Synchronous code
String news = gatherNewsReports(); // Can take a while.
print(news);
}
String gatherNewsReports(){
return "<gathered news goes here>";
}
String printWinningLotteryNumbers(){
return "Winning lotto numbers: [23, 63, 87, 26, 2]";
}
String printWeatherForecast(){
return "Tomorrow's forecast: 70F, sunny";
}
String printBaseballScore(){
return "Baseball score: Red Sox 10, Yankees 0";
}
void main(){
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
對(duì)應(yīng)輸出為:
<gathered news goes here>
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny
Baseball score: Red Sox 10, Yankees 0
使用說(shuō)明
Future 代表著在將來(lái)會(huì)獲取到一個(gè)值踊兜。
當(dāng)Future 被調(diào)用時(shí)竿滨,會(huì)發(fā)生:
- 將需要完成的工作進(jìn)行隊(duì)列化并返回一個(gè)Future 的對(duì)象。
- 當(dāng)待執(zhí)行的工作完成并獲取到最后的值后捏境,F(xiàn)uture 對(duì)象以這個(gè)值結(jié)束于游。
可以通過(guò)下面的方式獲取Future 的返回值。
- 使用async 和 await
- 使用Future 提供的API
使用async 和 await實(shí)現(xiàn)異步通信
async 和 await 是Dart 語(yǔ)言中異步編程支持的關(guān)鍵字垫言。使用這兩個(gè)關(guān)鍵字可以在不使用Future API 的情況下實(shí)現(xiàn)異步編程贰剥。
使用async 和 await實(shí)現(xiàn)異步通信的例子:
import 'dart:html';
import 'dart:async';
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');
}
// Imagine that this function is more complex and slow. :)
Future gatherNewsReports_async() async {
String path = 'https://www.dartlang.org/f/dailyNewsDigest.txt';
return (await HttpRequest.getString(path));
}
Future printDailyNewsDigest_async() async {
String news = await gatherNewsReports_async();
print(news);
}
void asynchronousCode(){
printDailyNewsDigest_async();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
main() {
asynchronousCode();
}
上面的例子對(duì)應(yīng)的輸出結(jié)果:
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny.
Baseball score: Red Sox 10, Yankees 0
<gathered news goes here>
上面代碼的執(zhí)行流程圖:
- 程序開(kāi)始執(zhí)行。
- 主函數(shù)調(diào)用
asynchronousCode()
函數(shù)筷频。 -
asynchronousCode()
函數(shù)調(diào)用printDailyNewsDigest_async()
函數(shù)蚌成,然后函數(shù)立即返回一個(gè)Future 對(duì)象。 -
asynchronousCode()
函數(shù)其它中接下來(lái)的代碼依次開(kāi)始執(zhí)行凛捏。以此執(zhí)行printWinningLotteryNumbers()
担忧,printWeatherForecast()
,printBaseballScore()
函數(shù)坯癣,并返回對(duì)應(yīng)的結(jié)果瓶盛。 -
printDailyNewsDigest_async()
函數(shù)體開(kāi)始執(zhí)行。 - 當(dāng)執(zhí)行到await 語(yǔ)句時(shí):程序暫停示罗,等待
gatherNewsReports_async()
函數(shù)執(zhí)行結(jié)果惩猫。 - 一旦
gatherNewsReports_async()
函數(shù)的Future 執(zhí)行完成,printDailyNewsDigest_async()
函數(shù)將繼續(xù)執(zhí)行蚜点。 - 當(dāng)
printDailyNewsDigest_async()
函數(shù)執(zhí)行完成后轧房,程序結(jié)束。
處理error
如果Future 的函數(shù)執(zhí)行中發(fā)生了error绍绘,怎Future 的返回值中就會(huì)包含error 信息奶镶。
可以通過(guò)try-catch 語(yǔ)句來(lái)處理這些異常迟赃。
處理異常的例子:
import 'dart:html';
import 'dart:async';
Future printDailyNewsDigest() async {
try {
String news = await gatherNewsReports();
print(news);
} catch (e) {
// ... handle error ...
}
}
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');
}
// Imagine that this function is more complex and slow. :)
Future gatherNewsReports() async {
String path =
'https://www.dartlang.org/f/dailyNewsDigest.txt';
String content = await HttpRequest.getString(path);
return content;
}
順序執(zhí)行
可以使用多個(gè)await 語(yǔ)句來(lái)確認(rèn)上一條一句結(jié)束了才執(zhí)行下面的語(yǔ)句。
例子如下:
// Sequential processing using async and await.
main() async {
await expensiveA();
await expensiveB();
doSomethingWith(await expensiveC());
}
Future API 實(shí)現(xiàn)異步通信
await / async 在Dart 1.9版本里面才添加進(jìn)來(lái)厂镇。
可以通過(guò)`then() 方法來(lái)注冊(cè)一個(gè)回調(diào)函數(shù)捺氢。這個(gè)回調(diào)函數(shù)將在Future 完成后開(kāi)始執(zhí)行。
處理error
在Future API 中提供了catchError()
方法來(lái)處理Future 執(zhí)行中的異常剪撬。
調(diào)用多個(gè)Future 類(lèi)型的返回值
使用多個(gè)then() 方法來(lái)鏈接多個(gè)函數(shù)。
expensiveA().then((aValue) => expensiveB())
.then((bValue) => expensiveC())
.then((cValue) => doSomethingWith(cValue));
上面的代碼等待expensiveA 執(zhí)行完成后開(kāi)始執(zhí)行expensiveB, 在expensiveB doSomethingWith悠反。
調(diào)用Future.wait() 方法來(lái)鏈接多個(gè)函數(shù)残黑。
// Parallel processing using the Future API
Future.wait([expensiveA(), expensiveB(), expensiveC()])
.then((List responses) => chooseBestResponse(responses))
.catchError((e) => handleError(e));
上面的代碼等待expensiveA(), expensiveB(), expensiveC() 都執(zhí)行完成后才開(kāi)始執(zhí)行then() 中的例子。
Asynchronous Programming: Streams
以下的內(nèi)容來(lái)源于下列地址:
https://www.dartlang.org/tutorials/language/streams
要點(diǎn)
- Stream 提供數(shù)據(jù)的異步隊(duì)列
- 數(shù)據(jù)隊(duì)列里面包含用戶交互數(shù)據(jù)斋否,或從文件中讀取的數(shù)據(jù)梨水。
- 可以使用
await for
或listen()
來(lái)處理stream 對(duì)象的數(shù)據(jù)。 - Stream API 提供錯(cuò)誤處理茵臭。
- 包含兩種類(lèi)型的Stream:?jiǎn)蝹€(gè)訂閱疫诽,廣播Stream
接受Stream 事件
雖然Stream 對(duì)象的創(chuàng)建有很多種方法,但是使用方法卻是相同的旦委。使用方法: 使用 await for
語(yǔ)句去操作一個(gè)Stream 對(duì)象的事件的迭代對(duì)象奇徒,就像for 循環(huán)操作迭代對(duì)象一樣。
await for
語(yǔ)句只能操作使用async
關(guān)鍵字標(biāo)記的函數(shù)缨硝。
例子如下:
import 'dart:async';
Future<int> sumStream(Stream<int> stream) async {
var sum = 0;
await for (var value in stream) {
sum += value;
}
return sum;
}
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
yield i;
}
}
main() async {
var stream = countStream(10);
var sum = await sumStream(stream);
print(sum); // 55
}
錯(cuò)誤事件
當(dāng)沒(méi)有收到新的事件時(shí)摩钙,Stream 對(duì)象會(huì)結(jié)束運(yùn)行。
當(dāng)接受到新事件的時(shí)候查辩,系統(tǒng)胡通知Stream 收到了新的事件胖笛。
當(dāng)讀取到的Stream 事件在await for 循環(huán)執(zhí)行時(shí),當(dāng)Stream 結(jié)束后宜岛,await for 循環(huán)也就結(jié)束了长踊。
當(dāng)Stream 對(duì)象運(yùn)行過(guò)程中有錯(cuò)誤發(fā)生,大部分的Stream 將停止萍倡。同時(shí)Stream 對(duì)象將至少發(fā)送一條錯(cuò)誤信息身弊。
可以使用try-catch 語(yǔ)句間await for 語(yǔ)句包括起來(lái),用這種方法來(lái)處理error 信息遣铝。
處理Stream 錯(cuò)誤的例子:
import 'dart:async';
Future<int> sumStream(Stream<int> stream) async {
var sum = 0;
try {
await for (var value in stream) {
sum += value;
}
} catch (error) {
return -1;
}
return sum;
}
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
if (i == 4) {
throw "Whoops!"; // Intentional error
} else {
yield i;
}
}
}
main() async {
var stream = countStream(10);
var sum = await sumStream(stream);
print(sum); // -1
}
Stream 對(duì)象處理
可以很方便的通過(guò)Stream 的await for 循環(huán)來(lái)依次處理相應(yīng)的事件佑刷。
下面的例子,可以方便找到 數(shù)值 > 0的數(shù)值的下標(biāo)位置酿炸。
import 'dart:async';
Future<int> lastPositive(Stream<int> stream) async {
var lastValue = null;
await for (var value in stream) {
if (value < 0) continue;
lastValue = value;
}
return lastValue;
}
main() async {
var data = [1, -2, 3, -4, 5, -6, 7, -8, 9, -10];
var stream = new Stream.fromIterable(data);
var lastPos = await lastPositive(stream);
print(lastPos); // 9
}
Stream 兩種類(lèi)型
單個(gè)訂閱類(lèi)型 (Single subscription streams)
大部分的Stream 實(shí)例會(huì)包含整個(gè)事件隊(duì)列的一部分瘫絮。每一個(gè)事件必須在正確的位置,并且不允許有任何數(shù)據(jù)遺失填硕。這種類(lèi)型類(lèi)似于閱讀文件或接受網(wǎng)頁(yè)服務(wù)麦萤。
這是類(lèi)似于TCP socket鹿鳖,不允許有數(shù)據(jù)遺失。
這種類(lèi)型的Stream壮莹,只能被監(jiān)聽(tīng)一次翅帜。
假如再次監(jiān)聽(tīng),將會(huì)導(dǎo)致之前的事件隊(duì)列丟失命满,并導(dǎo)致Stream 不再接受數(shù)據(jù)涝滴。
廣播類(lèi)型(Broadcast streams)
這種類(lèi)型的Stream 可以只一次處理一個(gè)事件。
可以對(duì)這種類(lèi)型實(shí)施多次監(jiān)聽(tīng)胶台。
Stream 的處理方法
完整方法列表:
返回值 | 函數(shù) |
---|---|
Future<T\> |
get first |
Future<T> |
get last |
Future<T> |
get single |
Future<int> |
get length |
Future<bool> |
get isEmpty |
Future<T> |
firstWhere(bool test(T event), {T orElse()}) |
Future<T> |
lastWhere(bool test(T event), {T orElse()}) |
Future<T> |
singleWhere(bool test(T event), {T orElse()}) |
Future<T> |
reduce(T combine(T previous, T element)) |
Future |
fold(initialValue, combine(previous, T element)) |
Future<String> |
join([String separator = ""]) |
Future<bool> |
contains(Object needle) |
Future |
forEach(void action(T element)) |
Future<bool> |
every(bool test(T element)) |
Future<bool> |
any(bool test(T element)) |
Future<List<T>> |
toList() |
Future<Set<T>> |
toSet() |
Future<T> |
elementAt(int index) |
Future |
pipe(StreamConsumer<T> consumer) |
Future |
drain([var futureValue]) |
簡(jiǎn)單的實(shí)例:
Future<bool> contains(Object element) async {
await for (var event in this) {
if (event == element) return true;
}
return false;
}
Future forEach(void action(T element)) async {
await for (var event in this) {
action(event);
}
}
Future<List<T>> toList() async {
var result = <T>[];
await this.forEach(result.add);
return result;
}
Future<String> join([String separator = ""]) async {
return (await this.toList()).join(separator);
}
Stream 對(duì)象的修改方法
方法列表:
返回值 | 函數(shù) |
---|---|
Stream<T> |
where(bool test(T event)) |
Stream |
map(convert(T event)) |
Stream |
expand(Iterable expand(T element); |
Stream<T> |
take(int count) |
Stream<T> |
skip(int count) |
Stream<T> |
takeWhile(bool test(T element)) |
Stream<T> |
skipWhile(bool test(T element)) |
Stream<T> |
distinct([bool equals(T previous, T next)]) |
Stream |
asyncExpand(Stream expand(T element)) |
Stream |
asyncMap(Future convert(T event)) |
Stream |
timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) |
Stream<T> |
handleError(Function onError, {bool test(error)}) |
Stream |
transform(StreamTransformer<T, dynamic> streamTransformer) |
使用這些函數(shù)歼疮,閱讀文件的例子:
import 'dart:io';
import 'dart:async';
import 'dart:convert';
main(args) async {
var file = new File(args[0]);
var lines = file
.openRead()
.transform(UTF8.decoder)
.transform(const LineSplitter());
await for (var line in lines) {
if (!line.startsWith('#')) {
print(line);
}
}
}
The listen() method
Stream 的listen() 方法是更底層的方法,其它的Stream的方法都是在listen 之上定義的诈唬。
創(chuàng)建一個(gè)Stream 類(lèi)型時(shí)韩脏,可以只繼承Stream 類(lèi),并實(shí)現(xiàn)listen 方法铸磅。