Dart API 學(xué)習(xí)記錄(二)

Dart API 學(xué)習(xí)記錄(一) http://www.itdecent.cn/p/388d986c0f48

Dart API 學(xué)習(xí)記錄(二)

dart:async

dart:async庫是Dart 語言支持異步編程的基礎(chǔ)。
庫中提供了Future 類和Stream 類。這兩個類是理解Dart 語言異步機(jī)制的基礎(chǔ)。

在使用前async 庫的功能前需要在代碼中添加如下語句:

import 'dart:async'

Future 類

Future 對象返回值表明當(dāng)前時刻的計算結(jié)果可能還不可用。
Future 實例會在計算結(jié)束后再返回結(jié)果,而不是現(xiàn)在立即返回。

Future 通常用來操作冗長的計算,比如大規(guī)模的I/O 操作或與用戶進(jìn)行交互。

下面的例子將返回一個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注冊了一個回調(diào)函數(shù),當(dāng)bind() 方法執(zhí)行完成后開始運行?;卣{(diào)函數(shù)的功能是: 當(dāng)bind()執(zhí)行成功后會返回一個HttpServer 的對象,在回調(diào)函數(shù)中會返回該HttpServer的一個熟悉值。

Stream 類

一個Stream 對象提供了一個異步數(shù)據(jù)的隊列。在這個隊列中可能包含事件(鼠標(biāo)點擊),大數(shù)據(jù)塊.

利用Stream 方法來讀取文件的例子:

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)容來源于下列地址:
https://www.dartlang.org/tutorials/language/futures

要點總結(jié)

  • Dart 語言是單線程的。
  • 同步的代碼可能導(dǎo)致代碼阻塞。
  • 可以使用Future 方法來執(zhí)行異步操作。
  • 在異步方法里使用await()來暫停代碼執(zhí)行,直到Future 執(zhí)行完成。
  • 也可使用Future 的then()方法來實現(xiàn)上面的目的。
  • 在異步方法里使用try...catch...來獲取異常。
  • 也可是使用Future 的catchError()方法來實現(xiàn)上面的目的。
  • 可以就多個異步的方法鏈接起來順序執(zhí)行。

簡介

可能導(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();
}

對應(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

使用說明

Future 代表著在將來會獲取到一個值。
當(dāng)Future 被調(diào)用時,會發(fā)生:

  1. 將需要完成的工作進(jìn)行隊列化并返回一個Future 的對象。
  2. 當(dāng)待執(zhí)行的工作完成并獲取到最后的值后,F(xiàn)uture 對象以這個值結(jié)束。

可以通過下面的方式獲取Future 的返回值。

  1. 使用async 和 await
  2. 使用Future 提供的API

使用async 和 await實現(xiàn)異步通信

async 和 await 是Dart 語言中異步編程支持的關(guān)鍵字。使用這兩個關(guān)鍵字可以在不使用Future API 的情況下實現(xiàn)異步編程。

使用async 和 await實現(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();
}

上面的例子對應(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í)行流程圖:


async-await
  1. 程序開始執(zhí)行。
  2. 主函數(shù)調(diào)用asynchronousCode()函數(shù)。
  3. asynchronousCode()函數(shù)調(diào)用printDailyNewsDigest_async()函數(shù),然后函數(shù)立即返回一個Future 對象。
  4. asynchronousCode()函數(shù)其它中接下來的代碼依次開始執(zhí)行。以此執(zhí)行printWinningLotteryNumbers(),printWeatherForecast(),printBaseballScore()函數(shù),并返回對應(yīng)的結(jié)果。
  5. printDailyNewsDigest_async()函數(shù)體開始執(zhí)行。
  6. 當(dāng)執(zhí)行到await 語句時:程序暫停,等待gatherNewsReports_async()函數(shù)執(zhí)行結(jié)果。
  7. 一旦gatherNewsReports_async()函數(shù)的Future 執(zhí)行完成,printDailyNewsDigest_async()函數(shù)將繼續(xù)執(zhí)行。
  8. 當(dāng)printDailyNewsDigest_async()函數(shù)執(zhí)行完成后,程序結(jié)束。

處理error

如果Future 的函數(shù)執(zhí)行中發(fā)生了error,怎Future 的返回值中就會包含error 信息。
可以通過try-catch 語句來處理這些異常。

處理異常的例子:

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í)行

可以使用多個await 語句來確認(rèn)上一條一句結(jié)束了才執(zhí)行下面的語句。

例子如下:

// Sequential processing using async and await.
main() async {
  await expensiveA();
  await expensiveB();
  doSomethingWith(await expensiveC());
}

Future API 實現(xiàn)異步通信

await / async 在Dart 1.9版本里面才添加進(jìn)來。

可以通過`then() 方法來注冊一個回調(diào)函數(shù)。這個回調(diào)函數(shù)將在Future 完成后開始執(zhí)行。

處理error

在Future API 中提供了catchError()方法來處理Future 執(zhí)行中的異常。

調(diào)用多個Future 類型的返回值

使用多個then() 方法來鏈接多個函數(shù)。
expensiveA().then((aValue) => expensiveB())
            .then((bValue) => expensiveC())
            .then((cValue) => doSomethingWith(cValue));

上面的代碼等待expensiveA 執(zhí)行完成后開始執(zhí)行expensiveB, 在expensiveB doSomethingWith。

調(diào)用Future.wait() 方法來鏈接多個函數(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í)行完成后才開始執(zhí)行then() 中的例子。

Asynchronous Programming: Streams

以下的內(nèi)容來源于下列地址:
https://www.dartlang.org/tutorials/language/streams

要點

  1. Stream 提供數(shù)據(jù)的異步隊列
  2. 數(shù)據(jù)隊列里面包含用戶交互數(shù)據(jù),或從文件中讀取的數(shù)據(jù)。
  3. 可以使用await forlisten()來處理stream 對象的數(shù)據(jù)。
  4. Stream API 提供錯誤處理。
  5. 包含兩種類型的Stream:單個訂閱,廣播Stream

接受Stream 事件

雖然Stream 對象的創(chuàng)建有很多種方法,但是使用方法卻是相同的。使用方法: 使用 await for語句去操作一個Stream 對象的事件的迭代對象,就像for 循環(huán)操作迭代對象一樣。

await for語句只能操作使用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
}

錯誤事件

當(dāng)沒有收到新的事件時,Stream 對象會結(jié)束運行。
當(dāng)接受到新事件的時候,系統(tǒng)胡通知Stream 收到了新的事件。
當(dāng)讀取到的Stream 事件在await for 循環(huán)執(zhí)行時,當(dāng)Stream 結(jié)束后,await for 循環(huán)也就結(jié)束了。

當(dāng)Stream 對象運行過程中有錯誤發(fā)生,大部分的Stream 將停止。同時Stream 對象將至少發(fā)送一條錯誤信息。
可以使用try-catch 語句間await for 語句包括起來,用這種方法來處理error 信息。

處理Stream 錯誤的例子:

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 對象處理

可以很方便的通過Stream 的await for 循環(huán)來依次處理相應(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 兩種類型

單個訂閱類型 (Single subscription streams)

大部分的Stream 實例會包含整個事件隊列的一部分。每一個事件必須在正確的位置,并且不允許有任何數(shù)據(jù)遺失。這種類型類似于閱讀文件或接受網(wǎng)頁服務(wù)。
這是類似于TCP socket,不允許有數(shù)據(jù)遺失。

這種類型的Stream,只能被監(jiān)聽一次。
假如再次監(jiān)聽,將會導(dǎo)致之前的事件隊列丟失,并導(dǎo)致Stream 不再接受數(shù)據(jù)。

廣播類型(Broadcast streams)

這種類型的Stream 可以只一次處理一個事件。
可以對這種類型實施多次監(jiān)聽。

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])

簡單的實例:

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 對象的修改方法

方法列表:

返回值 函數(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)建一個Stream 類型時,可以只繼承Stream 類,并實現(xiàn)listen 方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 異步編程對JavaScript語言太重要。Javascript語言的執(zhí)行環(huán)境是“單線程”的,如果沒有異步編程,根本...
    呼呼哥閱讀 7,399評論 5 22
  • 本文是對 Dart 語言的官方文檔做了簡單的翻譯和總結(jié),有不當(dāng)之處敬請指正。如果有時間和精力建議通讀官方文檔 he...
    小小小超子閱讀 10,886評論 8 22
  • 此文章是v1.0+時編寫,年代久遠(yuǎn),小心有毒,謹(jǐn)慎食用?。。?一些重要概念 所有的東西都是對象,所有的對象都是類的...
    soojade閱讀 10,216評論 2 27
  • 和Lydia去看了期待已久的烏托邦
    我說你瞅啥呀閱讀 176評論 0 0

友情鏈接更多精彩內(nèi)容