Future常用的異步函數(shù)
Future是一種表示可能異步返回值的對象。當我們需要執(zhí)行一個可能會阻塞主線程的操作時,可以使用Future來使這個操作異步執(zhí)行,這樣就不會阻塞UI線程。
一、 異步函數(shù)
Future:
Future是一種表示可能會返回結果的未來值的對象??梢允褂胊sync和await關鍵字來處理Future。
Future fetchData() async {
// 模擬耗時操作
await Future.delayed(Duration(seconds: 2));
return 'Data fetched successfully!';
}
void main() async {
print('Fetching data...');
String data = await fetchData();
print(data);
}
async和await:
async關鍵字用于修飾函數(shù),表示該函數(shù)是一個異步函數(shù),可以在其中使用await關鍵字來等待異步操作的結果。
Future fetchData() async {
// 模擬耗時操作
await Future.delayed(Duration(seconds: 2));
return 'Data fetched successfully!';
}
void main() async {
print('Fetching data...');
String data = await fetchData();
print(data);
}
Future.delayed:
可以使用Future.delayed創(chuàng)建一個延遲一段時間后返回結果的Future。
void main() async {
print('Start');
await Future.delayed(Duration(seconds: 2), () {
print('Delayed action');
});
print('End');
}
Future.wait:
如果需要同時等待多個異步操作完成,可以使用Future.wait。
Future fetchUser() {
return Future.delayed(Duration(seconds: 2), () => 'User fetched');
}
Future fetchPosts() {
return Future.delayed(Duration(seconds: 3), () => 'Posts fetched');
}
void main() async {
print('Fetching data...');
List> futures = [fetchUser(), fetchPosts()];
List results = await Future.wait(futures);
print(results);
}
Future.value:
是Flutter中的一個靜態(tài)方法,用于創(chuàng)建一個已經(jīng)完成(已解析)的Future對象,該對象的結果值為指定的值。
Future.value()方法的作用是立即返回一個已經(jīng)完成的Future對象,且該Future對象的結果值就是指定的value值。這意味著可以通過該Future對象進行異步操作的編程模型,如使用await關鍵字等。
void main() async {
Future future = Future.value(42);
int result = await future;
print(result); // 輸出: 42
}
在上述示例中,F(xiàn)uture.value(42)會創(chuàng)建一個已經(jīng)完成的Future對象,結果值為42。通過await關鍵字,可以等待該Future對象的結果,然后將結果賦值給result變量,并打印出結果值42。
Future.value()方法在某些情況下非常有用,例如將同步的結果值轉換為Future對象,或者作為其他異步操作的初始值。它提供了一種簡便的方式來創(chuàng)建并返回一個已經(jīng)完成的Future對象。
Future.doWhile:
Future.doWhile 是 Future 類的一個實例方法,用于執(zhí)行一個異步操作的循環(huán),直到指定的條件不再滿足為止。
Future doWhile(FutureOr Function() action)
參數(shù) action 是一個回調函數(shù),它將被反復調用執(zhí)行,直到返回的結果為 false?;卣{函數(shù) action 可以是一個 Future 類型的函數(shù),也可以是一個同步函數(shù)。
使用 Future.doWhile 方法可以實現(xiàn)異步的循環(huán)操作,以處理某些需要重復執(zhí)行的異步任務,直到條件不再滿足為止。
void main() async {
int count = 0;
await Future.doWhile(() async {
await Future.delayed(Duration(seconds: 1));
count++;
print(count);
return count < 5;
});
print('Loop completed');
}
Future.forEach:
Future.forEach 是 Future 類的一個實例方法,用于對一個集合進行異步迭代操作,并對集合中的每個元素執(zhí)行指定的異步操作。
Future forEach(void Function(T element) action)
參數(shù) action 是一個回調函數(shù),它將被異步調用以處理集合中的每個元素。回調函數(shù) action 接受一個參數(shù) element,表示集合中的當前元素。
使用 Future.forEach 方法可以方便地對集合進行異步迭代操作,處理集合中的每個元素的異步任務,等待所有的任務完成后返回一個 Future 對象。
void main() async {
List numbers = [1, 2, 3, 4, 5];
await Future.forEach(numbers, (int number) async {
await Future.delayed(Duration(seconds: 1));
print(number);
});
print('Iteration completed');
}
Future.microtask:
Future.microtask 是 Future 類的一個靜態(tài)方法,用于將一個微任務(microtask)添加到事件循環(huán)中,在當前事件循環(huán)的微任務隊列中立即執(zhí)行。
微任務是指一種高優(yōu)先級的任務,它會在事件循環(huán)的任務隊列中的其他任務之前執(zhí)行。使用 Future.microtask 方法可以將一個回調函數(shù)添加到當前微任務隊列中,以便在當前事件循環(huán)中的其他任務執(zhí)行完成后立即執(zhí)行。
static Future microtask(FutureOr computation())
參數(shù) computation 是一個回調函數(shù),它將被添加到當前微任務隊列中執(zhí)行?;卣{函數(shù) computation 可以是一個 Future 類型的函數(shù),也可以是一個同步函數(shù)。
使用 Future.microtask 方法可以在當前事件循環(huán)的微任務隊列中執(zhí)行一些高優(yōu)先級的任務,而不會延遲其他任務的執(zhí)行。
void main() {
print('Start');
Future.microtask(() {
print('Inside microtask');
});
print('End');
}
在上述示例中,我們在 main 函數(shù)中使用 Future.microtask 方法添加了一個微任務。該微任務會在當前事件循環(huán)的任務隊列中的其他任務執(zhí)行完成后立即執(zhí)行。因此,在打印 "Start" 和 "End" 之間,微任務中的回調函數(shù)會被執(zhí)行,打印出 "Inside microtask"。
需要注意的是,F(xiàn)uture.microtask 方法的回調函數(shù)在當前事件循環(huán)中的微任務隊列中執(zhí)行,因此不會創(chuàng)建新的事件循環(huán),也不會引發(fā)事件循環(huán)的重新調度。這使得微任務的執(zhí)行速度非???,適用于需要立即執(zhí)行的高優(yōu)先級任務,例如狀態(tài)更新、回調通知等。
另外,需要注意避免濫用 Future.microtask 方法,以免阻塞事件循環(huán)的正常執(zhí)行。只有在必要的情況下,才應該使用微任務。
Future.sync:
Future.sync 是 Future 類的一個靜態(tài)方法,用于創(chuàng)建一個同步執(zhí)行的 Future 對象。
static Future sync(T computation())
參數(shù) computation 是一個回調函數(shù),它將在當前執(zhí)行上下文中同步執(zhí)行?;卣{函數(shù) computation 可以是一個任意類型的函數(shù),返回值類型為 T。
使用 Future.sync 方法可以將同步的計算操作封裝為一個 Future 對象,以便與異步操作進行一致的編程模型。
void main() {
Future future = Future.sync(() {
return 42;
});
future.then((value) {
print(value); // 輸出: 42
});
print('End');
}
在上述示例中,我們使用 Future.sync 方法創(chuàng)建了一個同步的 Future 對象。回調函數(shù)中的計算操作直接返回了一個整數(shù)值 42。通過 future.then 方法,我們可以注冊一個回調函數(shù),當 Future 對象完成時將被調用。在回調函數(shù)中,我們打印出了 Future 對象的結果值 42。
需要注意的是,盡管 Future.sync 方法的回調函數(shù)是同步執(zhí)行的,但返回的 Future 對象仍然具有異步的特性,因為它是 Future 類的實例。因此,可以在返回的 Future 對象上使用異步的方法和操作,例如 then、catchError 等。
另外,由于 Future.sync 方法的回調函數(shù)是在當前執(zhí)行上下文中同步執(zhí)行的,所以在回調函數(shù)中避免進行長時間的阻塞操作,以免影響整個應用程序的響應性。
二、 異步組件
在Flutter中,有一些用于處理異步操作的常用組件。這些組件可用于優(yōu)化用戶界面,顯示加載狀態(tài),處理錯誤等。以下是一些常用的異步組件:
1、 FutureBuilder:
用于根據(jù) Future 的不同狀態(tài)構建界面。它接收一個 Future 對象,并根據(jù)異步操作的狀態(tài)(未完成、完成、出錯)來構建相應的UI。
Future fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'Data fetched successfully';
}
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Data: ${snapshot.data}');
}
},
);
}
2、 StreamBuilder:
用于監(jiān)聽 Stream 的事件并構建相應的UI。它接收一個 Stream 對象,并根據(jù)數(shù)據(jù)流的事件(數(shù)據(jù)、錯誤、完成)來構建界面。
Stream countStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
Widget build(BuildContext context) {
return StreamBuilder(
stream: countStream(),
initialData: 0,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Count: ${snapshot.data}');
}
},
);
}
3、 RefreshIndicator:
提供了下拉刷新的功能,用于更新顯示的數(shù)據(jù)。它通常與一個 ListView 或 GridView 組件結合使用。
List<String> dataList = ['Item 1', 'Item 2', 'Item 3'];
Future<void> refreshData() async {
await Future.delayed(Duration(seconds: 2));
setState(() {
dataList = ['Updated Item 1', 'Updated Item 2', 'Updated Item 3'];
});
}
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: refreshData,
child: ListView.builder(
itemCount: dataList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(dataList[index]),
);
},
),
);
}
4、 StreamBuilder 和 FutureBuilder 的衍生組件:
Flutter社區(qū)提供了許多基于 StreamBuilder 和 FutureBuilder 的衍生組件,用于處理更特定的異步場景,例如:
BlocBuilder:與狀態(tài)管理庫(如BLoC、Provider、Riverpod等)結合使用,用于構建基于數(shù)據(jù)流的界面。ValueListenableBuilder:用于監(jiān)聽ValueListenable對象的變化并構建相應的界面。`Animated
Builder:根據(jù)動畫的值來構建界面,通常與 AnimationController` 和其他動畫類一起使用。
三、 Flutter處理異步操作的結果和錯誤
在Flutter中,Future 類提供了許多方法來處理異步操作的結果和錯誤。以下是這些方法的說明:
1、 then:
注冊一個回調函數(shù),該函數(shù)會在異步操作成功完成時被調用,并接收異步操作的結果作為參數(shù)。
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'Data fetched successfully';
}
fetchData().then((data) {
print(data);
});
2、 catchError 或 onError:
注冊一個回調函數(shù),該函數(shù)會在異步操作發(fā)生錯誤時被調用,并接收錯誤信息作為參數(shù)。
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
throw Exception('Error occurred');
}
fetchData().catchError((error) {
print('Error: $error');
});
3、 error:
獲取異步操作的錯誤信息,如果異步操作發(fā)生錯誤的話。
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
throw Exception('Error occurred');
}
fetchData().then((data) {
print(data);
}).catchError((error) {
print('Error: ${error.toString()}');
});
4、 whenComplete:
注冊一個回調函數(shù),在異步操作完成時(不管成功或失?。┍徽{用,不接收任何參數(shù)。
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'Data fetched successfully';
}
fetchData().then((data) {
print(data);
}).catchError((error) {
print('Error: $error');
}).whenComplete(() {
print('Async operation completed');
});
5、 timeout:
設置異步操作的超時時間,并返回一個新的 Future,如果超時則會觸發(fā)錯誤。
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 5));
return 'Data fetched successfully';
}
fetchData().timeout(Duration(seconds: 3), onTimeout: () {
throw TimeoutException('Operation timed out');
}).then((data) {
print(data);
}).catchError((error) {
print('Error: $error');
});