在Dart中我們可以使用 async
來代表這是一個非同步的function
Future<String> fetchData2() async => 'data';
這裡的重點是:
就算我沒有另外用 Future
的constructor「 只要是 async function
就是會回傳Future
」,因為執行緒會用非同步的方式處理的話那也就表示他並不會馬上被執行,也代表我在處理它時勢必要用Future
在處理。
回到昨天的問題「我該如何將Future
裡的值取出來放到別的變數」
其實也很簡單就是使用 await
這個語法:
final data = await fetchData();
print('$data');
但另外一個重點是 await
必須要在 async function
才能使用。
void main(List<String> arguments) async {
final data = await fetchData();
print('$data');
}
await
是一種讓我們在非同步裡使用同步的語法,意思是被加上await
的會用同步的方式在運行:
print('n1');
final data = await outputAfter3s('asyncData1');
print('n2');
final data2 = await outputAfter3s('asyncData2');
print('n3');
print('$data');
print('$data2');
輸出會變成這樣:
n1
// 停頓3秒
n2
// 停頓3秒
n3
asyncData1
asyncData2
表示await
真的會使這個function 停頓三秒後再繼續往下執行,但這樣子是不是代表我整個程式都會因此被停住三秒?
我們另外宣告一個async function
並把這些非同步操作移出去:
void fetch() async {
print('n1');
final data = await outputAfter3s('asyncData1');
print('n2');
final data2 = await outputAfter3s('asyncData2');
print('n3');
print('$data');
print('$data2');
}
void main(List<String> arguments) {
fetch();
print('Hello world');
}
還記得前面所說的「 只要是 async function
就是會回傳Future
」嗎,沒錯雖然對於這個function他是會被當作用同步的方式在執行,但對於其他function 這個async function
還是非同步的,只有在async function
裡剩下的程式碼會被阻塞住。
n1
Hello world
// 停頓3秒
n2
// 停頓3秒
n3
asyncData1
那在async function
裡要如何做錯誤處理,其實就跟一般的錯誤處理一樣是使用 try catch
就好,也可以使用 finaly
用來當作try
裡面的code 執行完需要執行的部分。
try {
throwError();
final data = await fetchData();
print('$data');
} catch (err) {
print(err);
}finally {
print('done');
}
async/awiat 另外一個功用就是可以拿來處理 Stream
就如同我們用 for ... in
操作一個 List
,我們只要用 await for ... in
就可以拿來操作一個Stream
:
Future<int> getTotal(Stream<int> stream) async {
var total = 0;
await for (var number in stream) {
total += number;
}
return total;
}
// ...
print(await getTotal(_numberStream));
// 10
至於什麼Stream
可以先想像成一群 Future
,就像 List
那樣只是我們在迭代 List
時可以馬上獲得結果,但 Stream
沒辦法。
今天的程式碼:
https://github.com/zxc469469/dart-playground/tree/Day10/async-await
本來是預計Stream
與Async/Awiat 放到同一篇,只是打算放在同一篇但剛好遇到最近工作較忙只好切成兩篇來撐一下文章數了,導致這篇看起來有點水QQ
參考資料