Question #11MediumAsync ProgrammingImportant

Future (async, await) , Stream

#async#future#stream

Answer

Overview

Dart provides built-in support for asynchronous programming using Future, async/await, and Stream. These allow your app to do time-consuming work (like API calls or file I/O) without blocking the UI.


Future

A

text
Future
represents a single value that will be available at some point in the future — like a promise that a result is coming.

dart
Future<String> fetchUsername() async {
  await Future.delayed(Duration(seconds: 2)); // Simulate network delay
  return 'Alice';
}

void main() async {
  print('Fetching...');
  String name = await fetchUsername();
  print('Username: $name'); // Prints after 2 seconds
}

async / await

  • text
    async
    marks a function as asynchronous — it always returns a
    text
    Future
  • text
    await
    pauses execution inside the async function until the Future completes
dart
Future<void> loadData() async {
  try {
    final response = await http.get(Uri.parse('https://api.example.com/data'));
    final data = jsonDecode(response.body);
    print(data);
  } catch (e) {
    print('Error: $e');
  }
}

Without await (parallel execution)

dart
Future<void> loadParallel() async {
  // Both start simultaneously
  final userFuture = fetchUser();
  final postsFuture = fetchPosts();

  // Wait for both to complete
  final user = await userFuture;
  final posts = await postsFuture;
}

// Or with Future.wait
final results = await Future.wait([fetchUser(), fetchPosts()]);

Stream

A

text
Stream
is like a
text
Future
but emits multiple values over time — like a river of data. Use it for real-time updates, WebSockets, or Firestore listeners.

dart
// Creating a Stream
Stream<int> countDown() async* {
  for (int i = 5; i >= 0; i--) {
    await Future.delayed(Duration(seconds: 1));
    yield i; // Emit one value at a time
  }
}

// Consuming a Stream
void main() async {
  await for (int value in countDown()) {
    print(value); // 5, 4, 3, 2, 1, 0
  }
}

StreamController (Custom Stream)

dart
import 'dart:async';

final controller = StreamController<String>();

// Add data to stream
controller.sink.add('Hello');
controller.sink.add('World');

// Listen to stream
controller.stream.listen((data) {
  print(data); // Hello, World
});

// Always close when done
controller.close();

StreamBuilder in Flutter

dart
StreamBuilder<QuerySnapshot>(
  stream: FirebaseFirestore.instance.collection('messages').snapshots(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }
    if (snapshot.hasError) return Text('Error');
    final docs = snapshot.data!.docs;
    return ListView.builder(
      itemCount: docs.length,
      itemBuilder: (context, index) => ListTile(title: Text(docs[index]['text'])),
    );
  },
)

Future vs Stream

FeatureFutureStream
Values emittedOneMany (over time)
CompletionSingle resultCan be ongoing
Use caseHTTP request, DB readFirestore, WebSocket, timer
Flutter widget
text
FutureBuilder
text
StreamBuilder
Listen
text
await
/
text
.then()
text
await for
/
text
.listen()

Handling Errors

dart
// Future error handling
try {
  final data = await fetchData();
} catch (e) {
  print('Error: $e');
}

// Stream error handling
stream.listen(
  (data) => print(data),
  onError: (e) => print('Stream error: $e'),
  onDone: () => print('Stream closed'),
);

Key Principle: Use

text
Future
for a single async result. Use
text
Stream
for continuous/real-time data. Always handle errors and dispose of StreamControllers and subscriptions.