Dart?異步編程生成器及自定義類(lèi)型用法詳解
異步支持
今天介紹一下 Dart 學(xué)習(xí)的最后一節(jié)內(nèi)容,包括異步的使用、生成器語(yǔ)法以及類(lèi)型別名的使用。
Dart 類(lèi)庫(kù)有非常多的返回Future或者Stream對(duì)象的函數(shù)。 這些函數(shù)被稱(chēng)為異步函數(shù):它們只會(huì)在設(shè)置好一些耗時(shí)操作之后返回,比如像 IO 操作。而不是等到這個(gè)操作完成。
同時(shí),async和await關(guān)鍵詞支持了異步編程,允許您寫(xiě)出和同步代碼很像的異步代碼。
Future
Future與 JavaScript 中的Promise非常相似,表示一個(gè)異步操作的最終完成(或失?。┘捌浣Y(jié)果值的表示。簡(jiǎn)單來(lái)說(shuō),它就是用于處理異步操作的,異步處理成功了就執(zhí)行成功的操作,異步處理失敗了就捕獲錯(cuò)誤或者停止后續(xù)操作。一個(gè)Future 只會(huì)對(duì)應(yīng)一個(gè)結(jié)果,要么成功,要么失敗。
注: Future 的所有API的返回值仍然是一個(gè)Future對(duì)象,所以可以很方便的進(jìn)行鏈?zhǔn)秸{(diào)用。
Future.then
為了方便示例,在本例中使用Future.delayed 創(chuàng)建了一個(gè)延時(shí)任務(wù)(實(shí)際場(chǎng)景會(huì)是一個(gè)真正的耗時(shí)任務(wù),比如一次網(wǎng)絡(luò)請(qǐng)求),即2秒后返回結(jié)果字符串hi world!,然后我們?cè)?code>then中接收異步結(jié)果并打印結(jié)果,代碼如下:
Future.delayed(new Duration(seconds: 2),(){
return "hi world!";
}).then((data){
print(data);
});
Future.catchError
如果異步任務(wù)發(fā)生錯(cuò)誤,可以在catchError中捕獲錯(cuò)誤,將上面示例改為:
Future.delayed(new Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//執(zhí)行成功會(huì)走到這里
print("success");
}).catchError((e){
//執(zhí)行失敗會(huì)走到這里
print(e);
});
then方法還有一個(gè)可選參數(shù)onError,也可以它來(lái)捕獲異常:
Future.delayed(new Duration(seconds: 2), () {
//return "hi world!";
throw AssertionError("Error");
}).then((data) {
print("success");
}, onError: (e) {
print(e);
});
Future.whenComplete
有些時(shí)候,我們會(huì)遇到無(wú)論異步任務(wù)執(zhí)行成功或失敗都需要做一些事的場(chǎng)景,比如在網(wǎng)絡(luò)請(qǐng)求前彈出加載對(duì)話(huà)框,在請(qǐng)求結(jié)束后關(guān)閉對(duì)話(huà)框。這種場(chǎng)景,有兩種方法,第一種是分別在then或catch中關(guān)閉一下對(duì)話(huà)框,第二種就是使用Future的whenComplete回調(diào),我們將上面示例改一下:
Future.delayed(new Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//執(zhí)行成功會(huì)走到這里
print(data);
}).catchError((e){
//執(zhí)行失敗會(huì)走到這里
print(e);
}).whenComplete((){
//無(wú)論成功或失敗都會(huì)走到這里
});
Future.wait
使用Future.wait可以做到多個(gè)Future同時(shí)出發(fā)才會(huì)進(jìn)行后續(xù)操作,同 JavaScript 中的Promise.all()方法。
Future.wait接受一個(gè)Future數(shù)組參數(shù),只有數(shù)組中所有Future都執(zhí)行成功后,才會(huì)觸發(fā)then的成功回調(diào),只要有一個(gè)Future執(zhí)行失敗,就會(huì)觸發(fā)錯(cuò)誤回調(diào)。下面,我們通過(guò)模擬Future.delayed 來(lái)模擬兩個(gè)數(shù)據(jù)獲取的異步任務(wù),等兩個(gè)異步任務(wù)都執(zhí)行成功時(shí),將兩個(gè)異步任務(wù)的結(jié)果拼接打印出來(lái),代碼如下:
Future.wait([
// 2秒后返回結(jié)果
Future.delayed(new Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回結(jié)果
Future.delayed(new Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});
/*
最后會(huì)在4秒后拿到結(jié)果
*/
更多 Future 的 api 請(qǐng)自行查詢(xún)文檔。
async 和 await
異步函數(shù)是函數(shù)體被用async修飾符標(biāo)記的函數(shù)。 向函數(shù)中添加async關(guān)鍵字將使其返回一個(gè) Future。
String lookUpVersion() => '1.0.0'; // 返回String
Future<String> lookUpVersion() async => '1.0.0'; // 返回Future<String>
然后我們可以使用await關(guān)鍵字在內(nèi)部直接接受一個(gè) Future 的then的成功回調(diào),就如同 JavaScript 中的那樣:
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
// 執(zhí)行接下來(lái)的操作
} catch(e){
// 錯(cuò)誤處理
print(e);
}
}
async用來(lái)表示函數(shù)是異步的,定義的函數(shù)會(huì)返回一個(gè)Future對(duì)象,可以使用then方法添加回調(diào)函數(shù)。await后面是一個(gè)Future,表示等待該異步任務(wù)完成,異步完成后才會(huì)往下走。注意,await必須出現(xiàn)在async函數(shù)內(nèi)部。
注意: 函數(shù)的主體不需要使用 Future 的 API。如果需要,Dart 將創(chuàng)建 Future 的對(duì)象。如果沒(méi)有返回一個(gè)有用的值,那么將其返回Future<void>類(lèi)型。
處理流(Stream)
Stream 也是用于接收異步事件數(shù)據(jù),和Future 不同的是,它可以接收多個(gè)異步操作的結(jié)果(成功或失敗)。 也就是說(shuō),在執(zhí)行異步任務(wù)時(shí),可以通過(guò)多次觸發(fā)成功或失敗事件來(lái)傳遞結(jié)果數(shù)據(jù)或錯(cuò)誤異常。 Stream 常用于會(huì)多次讀取數(shù)據(jù)的異步任務(wù)場(chǎng)景,如網(wǎng)絡(luò)內(nèi)容下載、文件讀寫(xiě)等。
當(dāng)需要從 Stream 獲取值時(shí),有兩個(gè)選擇:
使用async和異步的for循環(huán)(await for)
注: 在使用await for之前,請(qǐng)確保它使代碼更清晰,并且確實(shí)希望等待流(Stream)的所有結(jié)果。例如,通常不應(yīng)該為 UI 事件使用await,因?yàn)?UI 框架會(huì)發(fā)送無(wú)窮無(wú)盡的事件流。
異步for循環(huán)有以下形式:
await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}
表達(dá)式的值必須具有 Stream 類(lèi)型。執(zhí)行過(guò)程如下:
等待流發(fā)出值。
執(zhí)行for循環(huán)的主體,并將變量設(shè)置為發(fā)出的值。
重復(fù)1和2,直到流關(guān)閉。
要停止偵聽(tīng)流,可以使用break或return語(yǔ)句,該語(yǔ)句將跳出for循環(huán),并從流中取消訂閱。
如果在實(shí)現(xiàn)異步for循環(huán)時(shí)出現(xiàn)編譯時(shí)錯(cuò)誤,請(qǐng)確保await在異步函數(shù)中。例如,要在應(yīng)用程序的main()函數(shù)中使用異步for循環(huán),main()的主體必須標(biāo)記為async:
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
使用Stream API,如[庫(kù)的引導(dǎo)]中的描述
Stream.fromFutures([
// 1秒后返回結(jié)果
Future.delayed(new Duration(seconds: 1), () {
return "hello 1";
}),
// 拋出一個(gè)異常
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回結(jié)果
Future.delayed(new Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
}, onDone: (){
});
/*
上面的代碼依次會(huì)輸出:
I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3
*/
生成器
當(dāng)需要延遲地生成一個(gè)值序列時(shí),請(qǐng)考慮使用生成器函數(shù)。
Dart 內(nèi)置支持兩種生成器函數(shù):
- 同步生成器:返回 Iterable 對(duì)象
- 異步生成器:返回 Stream 對(duì)象
要實(shí)現(xiàn)同步生成器函數(shù),將函數(shù)體標(biāo)記為sync*,并使用yield語(yǔ)句傳遞值:
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
要實(shí)現(xiàn)異步生成器函數(shù),將函數(shù)體標(biāo)記為async*,并使用yield語(yǔ)句傳遞值:
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
如果生成器是遞歸的,可以使用yield*來(lái)改進(jìn)它的性能:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
類(lèi)型定義
在 Dart 中,函數(shù)是對(duì)象,就像字符串和數(shù)字是對(duì)象一樣。typedef或function-type為函數(shù)提供一個(gè)類(lèi)型別名,可以在聲明字段和返回類(lèi)型時(shí)使用這個(gè)名稱(chēng)。當(dāng)函數(shù)類(lèi)型被分配給變量時(shí),typedef保留類(lèi)型信息。
以下代碼不使用typedef:
class SortedCollection {
Function compare;
SortedCollection(int f(Object a, Object b)) {
compare = f;
}
}
// Initial, broken implementation.
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
// All we know is that compare is a function,
// but what type of function?
assert(coll.compare is Function);
}
上面的代碼中,當(dāng)給compare分配f時(shí)類(lèi)型信息會(huì)丟失。f的類(lèi)型是(Object, Object)->int(int表示返回值類(lèi)型),當(dāng)然,compare的類(lèi)型是Function。如果我們更改代碼以使用顯式名稱(chēng)和保留類(lèi)型信息,開(kāi)發(fā)人員和工具都可以使用這些信息。
typedef Compare = int Function(Object a, Object b);
class SortedCollection {
Compare compare;
SortedCollection(this.compare);
}
// Initial, broken implementation.
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
assert(coll.compare is Function);
assert(coll.compare is Compare);
}
注意: 目前,typedefs僅限于函數(shù)類(lèi)型,可能在之后會(huì)有所改變。
因?yàn)?code>typedef僅僅是別名,所以它們提供了一種檢查任何函數(shù)類(lèi)型的方法。例如:
typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
assert(sort is Compare<int>); // True!
}
元數(shù)據(jù)
使用元數(shù)據(jù)提供關(guān)于代碼的附加信息。元數(shù)據(jù)注釋以字符@開(kāi)頭,后跟對(duì)編譯時(shí)常量(如deprecated)的引用或?qū)ΤA繕?gòu)造函數(shù)的調(diào)用。
所有 dart 代碼都可以使用兩個(gè)注釋?zhuān)?code>@deprecated(棄用注釋?zhuān)┖?code>@override。這里有一個(gè)使用@deprecated注釋的例子:
class Television {
/// _Deprecated: Use [turnOn] instead._
@deprecated
void activate() {
turnOn();
}
/// Turns the TV's power on.
void turnOn() {...}
}
可以定義自己的元數(shù)據(jù)注釋?zhuān)ㄒ簿褪穷?lèi)似 JavaScript 中的裝飾器的效果)。這里有一個(gè)定義帶有兩個(gè)參數(shù)的@todo注釋的示例:
library todo;
class Todo {
final String who;
final String what;
const Todo(this.who, this.what);
}
這里有一個(gè)使用@todo注釋的例子:
import 'todo.dart';
@Todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
元數(shù)據(jù)可以出現(xiàn)在庫(kù)、類(lèi)、類(lèi)型定義、類(lèi)型參數(shù)、構(gòu)造函數(shù)、工廠、函數(shù)、字段、參數(shù)或變量聲明之前,也可以出現(xiàn)在導(dǎo)入或?qū)С鲋噶钪???梢允褂梅瓷湓谶\(yùn)行時(shí)檢索元數(shù)據(jù)。
核心庫(kù)的使用
可以參考官方文檔中的介紹:A tour of the core libraries
以上就是Dart 異步編程生成器及自定義類(lèi)型用法詳解的詳細(xì)內(nèi)容,更多關(guān)于Dart 異步編程生成器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Flutter Dart快速排序算法示例詳解
- Flutter基于Dart Unwrapping Multiple Optional小技巧
- SafeList?in?Flutter?and?Dart小技巧
- Dart多態(tài)控制反轉(zhuǎn)編碼規(guī)范實(shí)例詳解
- Dart多個(gè)future隊(duì)列完成加入順序關(guān)系及原子性論證
- Dart語(yǔ)法之變量聲明與數(shù)據(jù)類(lèi)型實(shí)例詳解
- Flutter入門(mén)學(xué)習(xí)Dart語(yǔ)言變量及基本使用概念
- 一文詳解Dart如何實(shí)現(xiàn)多任務(wù)并行
相關(guān)文章
Dart語(yǔ)法之變量聲明與數(shù)據(jù)類(lèi)型實(shí)例詳解
這篇文章主要為大家介紹了Dart語(yǔ)法之變量聲明與數(shù)據(jù)類(lèi)型實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
Flutter入門(mén)學(xué)習(xí)Dart語(yǔ)言變量及基本使用概念
這篇文章主要為大家介紹了Flutter入門(mén)學(xué)習(xí)Dart語(yǔ)言變量及基本使用概念,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
Dart多態(tài)控制反轉(zhuǎn)編碼規(guī)范實(shí)例詳解
這篇文章主要為大家介紹了Dart多態(tài)控制反轉(zhuǎn)編碼規(guī)范實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Flutter學(xué)習(xí)筆記(一)配置環(huán)境
這篇文章主要介紹了Flutter學(xué)習(xí)筆記(一)配置環(huán)境,Flutter?app使用了?Dart語(yǔ)言,源自于?Google,現(xiàn)在是?ECMA?的標(biāo)準(zhǔn),需要的朋友可以參考下2023-04-04
Flutter SizedBox布局組件Widget使用示例詳解
這篇文章主要為大家介紹了Flutter SizedBox布局組件Widget使用示例詳解2023-02-02

