← Dart EnglishChapter 11 of 13

Async Programming

## Learning Objectives - Understand async programming concepts - Master Future and async/await - Work with Streams - Handle errors in async code ## Why Async? ### The Problem ```dart // Synchronous - blocks until complete void main() { print('Before'); var data = fetchData(); // Blocks for 5 seconds print(data); print('After'); } ``` ### The Solution ```dart // Asynchronous - doesn't block void main() async { print('Before'); var data = await fetchData(); // Non-blocking print(data); print('After'); } ``` ## Future ### Basic Concept ```dart void main() { // simulate async operation Future fetchData() { return Future.delayed(Duration(seconds: 2), () { return 'Data loaded'; }); } print('Before'); fetchData().then((data) { print(data); // Data loaded }); print('After'); // Prints before data (non-blocking) } ``` ### Future States 1. **Uncompleted**: Operation in progress 2. **Completed with value**: Success 3. **Completed with error**: Failure ## async and await ### Basic Syntax ```dart Future fetchUser() async { // Simulate network delay await Future.delayed(Duration(seconds: 1)); return 'Alice'; } void main() async { print('Fetching...'); String user = await fetchUser(); print('User: $user'); } ``` ### async Function Rules ```dart // async function always returns Future Future addOne(int n) async { await Future.delayed(Duration(milliseconds: 100)); return n + 1; } // void async - for side effects only Future process() async { await Future.delayed(Duration(seconds: 1)); print('Done'); } ``` ### Multiple awaits ```dart Future loadData() async { print('Loading...'); var user = await fetchUser(); var posts = await fetchPosts(user); print('User: $user'); print('Posts: $posts'); } ``` ## Error Handling ### Try-Catch ```dart Future fetchData() async { try { var result = await riskyOperation(); print('Success: $result'); } catch (e) { print('Error: $e'); } } Future riskyOperation() async { await Future.delayed(Duration(seconds: 1)); throw Exception('Failed!'); } ``` ### Catch Specific Errors ```dart Future process() async { try { await fetchData(); } on NetworkException { print('Network error'); } on ServerException catch (e) { print('Server error: $e'); } catch (e, stack) { print('Unexpected: $e'); print('Stack: $stack'); } } class NetworkException implements Exception {} class ServerException implements Exception { final String message; ServerException(this.message); } ``` ### Finally ```dart Future process() async { try { await fetchData(); } catch (e) { print('Error: $e'); } finally { // Always executes await cleanup(); } } ``` ## Future Methods ### then ```dart Future fetchNumber() async { return 42; } void main() { fetchNumber() .then((n) => n * 2) .then((n) => print('Result: $n')); // Result: 84 } ``` ### catchError ```dart Future fetchNumber() async { throw Exception('Error'); } void main() { fetchNumber() .catchError((e) => print('Caught: $e')) .then((n) => print('Number: $n')); // Caught: Exception: Error } ``` ### whenComplete ```dart Future process() async { await fetchData() .whenComplete(() => print('Cleanup done')); } ``` ### wait ```dart Future main() async { var futures = [ fetchUser(1), fetchUser(2), fetchUser(3), ]; var results = await Future.wait(futures); print('All users: $results'); } ``` ## Streams ### Stream Basics ```dart Stream countStream() async* { for (int i = 1; i <= 5; i++) { await Future.delayed(Duration(seconds: 1)); yield i; } } void main() async { await for (var value in countStream()) { print(value); // 1, 2, 3, 4, 5 (each second) } print('Done'); } ``` ### Stream Methods ```dart void main() { var stream = Stream.fromIterable([1, 2, 3, 4, 5]); // listen stream.listen((value) { print('Got: $value'); }); // map stream.map((n) => n * 2); // where stream.where((n) => n % 2 == 0); // take stream.take(3); } ``` ### Single Subscription Streams ```dart Stream countStream() async* { for (int i = 1; i <= 5; i++) { yield i; } } void main() async { var stream = countStream(); // Can only listen once stream.listen(print); // stream.listen(print); // Error: already listening } ``` ### Broadcast Streams ```dart class EventBus { final _controller = StreamController.broadcast(); Stream get stream => _controller.stream; void emit(String event) { _controller.add(event); } void dispose() { _controller.close(); } } void main() { var bus = EventBus(); bus.stream.listen((e) => print('Listener 1: $e')); bus.stream.listen((e) => print('Listener 2: $e')); bus.emit('Hello'); // Both listeners receive bus.dispose(); } ``` ## Async Patterns ### FutureBuilder (Flutter) ```dart // Flutter example FutureBuilder( future: fetchData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); } else if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); } else { return Text('Data: ${snapshot.data}'); } }, ) ``` ### StreamBuilder (Flutter) ```dart // Flutter example StreamBuilder( stream: countStream(), builder: (context, snapshot) { if (!snapshot.hasData) { return CircularProgressIndicator(); } return Text('Count: ${snapshot.data}'); }, ) ``` ## Common Async Operations ### timeout ```dart Future fetchData() async { return Future.delayed(Duration(seconds: 5), () => 'Data'); } void main() async { try { var result = await fetchData().timeout( Duration(seconds: 2), onTimeout: () => 'Timeout default', ); print(result); // Timeout default } catch (e) { print('Error: $e'); } } ``` ### retry ```dart Future fetchWithRetry() async { for (int i = 0; i < 3; i++) { try { return await fetchData(); } catch (e) { if (i == 2) rethrow; await Future.delayed(Duration(seconds: 1)); } } throw Exception('Failed'); } ``` ## Async vs Sync | Aspect | Async | Sync | |--------|-------|------| | Blocking | No | Yes | | Returns | Future | Value | | Keyword | async/await | None | | Error | try/catch | try/catch | | Use case | I/O, network | Computation | ## Summary - Future: represents a value available sometime later - `async` makes function return Future - `await` pauses until Future completes - Streams: sequence of async events - `async*` yields multiple values from stream - `listen` subscribes to streams - Handle errors with try/catch - `StreamController` creates streams programmatically

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →