# [異步編程](https://dart.dev/libraries/async/async-await) 相關主題 * [Streams](https://hackmd.io/@asdf121472/S12kHzZr1l) * [Concurrency](https://dart.dev/language/concurrency) * [Asynchrony support](https://dart.dev/language/async) * [videos](https://youtube.com/playlist?list=PLjxrf2q8roU0Net_g1NT5_vOO3s_FR02J&si=whZ5pcHq60gQNta1) * [Future class](https://api.dart.dev/dart-async/Future-class.html) * [Stream class](https://api.dart.dev/dart-async/Stream-class.html) * [Futures and error handling](https://dart.dev/libraries/async/futures-error-handling) * [dart:async](https://dart.dev/libraries/dart-async) ## 重要觀念 ### Future物件代表尚未執行完成的事件 ``` Future<String> fetchUserOrder() { return Future.delayed(Duration(seconds: 1), () => 'Large Latte'); } ``` 上列程式的回傳類型是 Future<回傳值類型>, 被呼叫時會立刻回傳`Instance of 'Future<String>'`給呼叫者, 直到 `Future.delayed`執行完成, 才會回傳真正的結果String: `'Large Latte'`, 所以以下程式列印不出 "Large Latte" ``` String createOrderMessage() { var order = fetchUserOrder(); return 'Your order is: $order'; } Future<String> fetchUserOrder() => // Imagine that this function is more complex and slow. Future.delayed( const Duration(seconds: 2), () => 'Large Latte', ); void main() { print(createOrderMessage()); //print: Your order is: Instance of 'Future<String>' } ``` ### async, async*, await **async**: 標示函數為異步函數(單一回傳值) **async***: 標示函數為異步Generator函數(多個回傳值) **Stream**: 異步Generator函數的返回值不只一個, 會儲存在Stream<回傳值類型> 中 ``` // Stream像是有多個值的可迭代物件 Stream<int> countStream(int max) async* { for (int i = 1; i <= max; i++) { // generator用 yield 返回值 yield i; } } ``` **await**: 用 ansyc, ansyc* 修飾的異步函數內部才能使用 await. await expression 會阻塞, 等待expression執行結束, 才繼續執行. **同步操作**:同步操作會阻止其他操作執行,直到完成為止。 **同步函數**:同步函數僅執行同步操作。 **異步操作**:異步操作一旦啟動,就允許其他操作在完成之前執行。 **異步函數**:異步函數至少執行一項異步操作,也可以執行同步操作。 ### What is a future? (以下以future 代表一個Future類的實例) Future 表示異步操作的結果,可以有3種狀態:未完成 或 已完成with value, 已完成with Error. 呼叫異步函數時,它會 **立刻** 回傳一個未完成的 future。該 future 正在等待函數異步操作完成或拋出錯誤。如果異步操作成功,future 將完成並附帶一個值。否則,它將完成並出現錯誤。 `Future<String>` 代表 future完成時會回傳一個String.`Future<void>` 代表完成時沒有回傳值.如果執行的異步操作因任何原因失敗,則回傳一個Error。 ### Execution within async functions ``` Future<void> printOrderMessage() async { print('Awaiting user order...'); var order = await fetchUserOrder(); print('Your order is: $order'); } Future<String> fetchUserOrder() { // Imagine that this function is more complex and slow. return Future.delayed(const Duration(seconds: 4), () => 'Large Latte'); } void main() async { countSeconds(4); await printOrderMessage(); } // You can ignore this function - it's here to visualize delay time in this example. void countSeconds(int s) { /* i=1 到 s的 futures 會立刻同時啟動, 每個future會執行完自己的延遲時間後 才print(i) 所以總共只延遲 s 秒 */ for (var i = 1; i <= s; i++) { Future.delayed(Duration(seconds: i), () => print(i)); } } /* print: Awaiting user order... 1 2 3 4 Your order is: Large Latte */ ``` ### [try-on-catch-finally](https://hackmd.io/@asdf121472/BJIOCHI1kl) 異步編程和一般編程相同, 可以用try-catch作錯誤處理 ``` Future<void> printOrderMessage() async { try { print('Awaiting user order...'); var order = await fetchUserOrder(); print(order); } catch (err) { print('Caught error: $err'); } } Future<String> fetchUserOrder() { // Imagine that this function is more complex. var str = Future.delayed( const Duration(seconds: 4), () => throw 'Cannot locate user order'); return str; } void main() async { await printOrderMessage(); } // print: // Awaiting user order... // Caught error: Cannot locate user order ```