24 Stream
I’ll teach you about Dart streams by comparing them with Python concepts you already know. This will help bridge your existing knowledge to Dart’s approach.
24.1 What are Streams?
Streams in Dart are similar to Python generators and async iterators. They represent a sequence of asynchronous events - data that arrives over time rather than all at once.
Traditional List: [1, 2, 3, 4, 5] (all data available immediately)
Stream: 1 → 2 → 3 → 4 → 5 (data arrives over time)
24.2 Python vs Dart Comparison
Let me show you the equivalent concepts:
24.2.1 Python Generator (Synchronous)
def count_generator(to):
for i in range(1, to + 1):
yield 2 * i
# Usage
= count_generator(10)
gen = sum(gen)
total print(total) # 110
24.2.2 Python Async Generator
import asyncio
async def count_async_generator(to):
for i in range(1, to + 1):
yield 2 * i
async def sum_async_gen(async_gen):
= 0
total async for value in async_gen:
+= value
total return total
async def main():
= count_async_generator(10)
stream = await sum_async_gen(stream)
total print(total) # 110
asyncio.run(main())
24.2.3 Dart Stream (Your Example)
Stream<int> countStream(int to) async* { // async* = async generator
for (int i = 1; i <= to; i++) {
yield 2*i; // Same yield keyword as Python
}
}
Future<int> sumStream(Stream<int> stream) async {
var sum = 0;
await for (final value in stream) { // await for = async for in Python
+= value;
sum }
return sum;
}
24.3 Key Dart Stream Concepts
24.3.1 1. Stream Creation (async*
and yield
)
// async* creates a stream generator (like Python's async def with yield)
Stream<String> dataStream() async* {
yield 'First'; // Emit single value
yield 'Second';
yield* anotherStream(); // yield* = yield from in Python
}
Python equivalent:
async def data_stream():
yield 'First'
yield 'Second'
yield from another_stream() # yield from
24.3.2 2. Stream Consumption (await for
)
// await for is like Python's async for
await for (final item in stream) {
print(item);}
Python equivalent:
async for item in stream:
print(item)
24.3.3 3. Stream Transformation (Like Python’s map, filter)
Stream<int> numbers = Stream.fromIterable([1, 2, 3, 4, 5]);
// Transform (like Python's map)
var doubled = numbers.map((n) => n * 2);
// Filter (like Python's filter)
var evenOnly = numbers.where((n) => n % 2 == 0);
// Chain operations (like Python's method chaining)
var result = numbers
.where((n) => n % 2 == 0)
.map((n) => n * 2);
Python equivalent:
= [1, 2, 3, 4, 5]
numbers
# Transform
= map(lambda n: n * 2, numbers)
doubled
# Filter
= filter(lambda n: n % 2 == 0, numbers)
even_only
# Chain (more Pythonic way)
= [n * 2 for n in numbers if n % 2 == 0] result
24.4 Analyzing Your Example
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
yield 2*i; // Yields: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20
}
}
This creates a stream that emits: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20
Sum = 2+4+6+8+10+12+14+16+18+20 = 110 (not 55 as commented)
24.5 Common Stream Patterns
24.5.1 1. Single-Subscription vs Broadcast Streams
// Single-subscription (like Python generator - can only iterate once)
Stream<int> singleUse = countStream(5);
// Broadcast (multiple listeners, like Python list)
Stream<int> broadcast = countStream(5).asBroadcastStream();
24.5.2 2. Stream Methods (Similar to Python’s itertools)
var stream = Stream.fromIterable([1, 2, 3, 4, 5]);
// Take first n (like itertools.islice)
var firstThree = stream.take(3);
// Skip first n
var skipTwo = stream.skip(2);
// Reduce (like Python's reduce)
var sum = await stream.reduce((a, b) => a + b);
// Convert to list (like list(generator) in Python)
var list = await stream.toList();
24.6 Real-World Example: HTTP Requests
Here’s how streams are useful for real-world async operations:
Stream<String> fetchDataStream() async* {
for (int page = 1; page <= 3; page++) {
// Simulate API call delay
await Future.delayed(Duration(seconds: 1));
yield 'Data from page $page';
}
}
void main() async {
'Starting data fetch...');
print(await for (final data in fetchDataStream()) {
'Received: $data');
print(}
'All data fetched!');
print(}
This is similar to Python’s approach of yielding results as they become available, rather than waiting for all data before returning.
The key insight is that Dart streams are essentially asynchronous iterators - just like Python’s async generators, but with more built-in methods for transformation and handling.