Dart: Stream في Dart
آخر تحديث: 2026-08-26
Stream هو نهر من البيانات — مستمر، تتم معالجته فور وصوله، لا حاجة للانتظار حتى وصول كل شيء دفعة واحدة.
1. ما ستتعلمه
- مفاهيم Stream: الاشتراك الأحادي مقابل البث
- إنشاء Stream: fromIterable / periodic / محول الأحداث
- العوامل: map / where / expand / take / skip / distinct
- StreamController و StreamSubscription
- سيناريو بوب: معالجة تدفق الطلبات في الوقت الفعلي لخط أنابيب البيانات
2. قصة مطور حقيقي
(1) نقطة الألم: ملايين سجلات البيانات لا يمكن تحميلها في الذاكرة دفعة واحدة
كان خط أنابيب البيانات الخاص ببوب يقوم في البداية بتحميل جميع الـ 1,200,000 طلب في الذاكرة للمعالجة عند التعامل مع طلبات التجارة الإلكترونية، مما أدى إلى ذروة ذاكرة 4 جيجابايت وتسبب في تحطم الخادم بخطأ OOM ثلاث مرات. علاوة على ذلك، مع استمرار وصول الطلبات في الوقت الفعلي، كان نموذج المعالجة الدفعية غير قادر على التعامل مع البيانات الواردة حديثاً.
(2) حل Stream
يسمح Stream بمعالجة البيانات قطعة قطعة مثل تدفق المياه: عالج واحدة فور وصولها، مع إبقاء استخدام الذاكرة مستقراً عند 50 ميجابايت. عوامل Stream (where/map/reduce) تتيح التعريف التصريحي لخط أنابيب المعالجة.
orderStream
.where((order) => order.status == 'completed')
.map((order) => order.amount)
.fold(0, (sum, amount) => sum + amount)
.then((total) => print('Revenue: \$$total USD'));
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
(3) الفوائد
- تم تخفيض الذاكرة من 4 جيجابايت إلى 50 ميجابايت، مما ألغى أخطاء OOM
- المعالجة في الوقت الفعلي للطلبات الواردة حديثاً، تم تقليل زمن الانتقال من "انتظار المعالجة الدفعية" إلى "ثوانٍ"
- سلاسل عوامل Stream تجعل منطق معالجة البيانات تصريحياً وقابلاً للتكوين
3. أساسيات Stream
(1) الاشتراك الأحادي مقابل البث
flowchart LR
A[مصدر البيانات] --> B["StreamController"]
B --> C["where() تصفية"]
C --> D["map() تحويل"]
D --> E["expand() تسطيح"]
E --> F["take() حد"]
F --> G["listen() استهلاك"]
subgraph خط أنابيب Stream
C
D
E
F
end
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
| النوع | المشتركون | إعادة التشغيل | حالة الاستخدام |
|---|---|---|---|
| Stream باشتراك أحادي | 1 | غير قابل لإعادة التشغيل | قراءة الملفات، استجابات HTTP |
| Stream بث | متعدد | غير قابل لإعادة التشغيل | أحداث واجهة المستخدم، البيانات في الوقت الفعلي |
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: أساسيات Stream
import 'dart:async';
void main() async {
// إنشاء stream من iterable
final stream = Stream.fromIterable([1, 2, 3, 4, 5]);
// الاستماع إلى stream
await for (final value in stream) {
print('Received: $value');
}
// بديل: الاستماع مع استدعاء
final stream2 = Stream.fromIterable(['ORD-001', 'ORD-002', 'ORD-003']);
stream2.listen(
(order) => print('Order: $order'),
onDone: () => print('Stream completed'),
onError: (e) => print('Error: $e'),
);
// انتظار اكتمال stream
await stream2.drain();
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
4. إنشاء Stream
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: إنشاء من fromIterable
import 'dart:async';
void main() async {
// من iterable - يصدر كل عنصر
final orders = Stream.fromIterable([
{'id': 'ORD-001', 'amount': 1500.0},
{'id': 'ORD-002', 'amount': 3200.0},
{'id': 'ORD-003', 'amount': 890.0},
]);
await for (final order in orders) {
print('Order: ${order['id']} - \$${order['amount']} USD');
}
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: إنشاء من periodic
import 'dart:async';
void main() async {
// Stream دوري - يصدر قيماً على فترات منتظمة
final ticker = Stream.periodic(
const Duration(seconds: 1),
(count) => 'Tick ${count + 1}',
);
// خذ أول 5 علامات فقط
await for (final tick in ticker.take(5)) {
print(tick);
}
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: إنشاء من StreamController
import 'dart:async';
void main() async {
final controller = StreamController<String>();
// إضافة بيانات إلى الـ stream
controller.add('ORD-001');
controller.add('ORD-002');
controller.add('ORD-003');
// إغلاق الـ stream عند الانتهاء
controller.close();
// استهلاك الـ stream
await for (final order in controller.stream) {
print('Processing: $order');
}
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
| طريقة الإنشاء | الصيغة | مصدر البيانات | حالة الاستخدام |
|---|---|---|---|
| fromIterable | Stream.fromIterable(list) |
مجموعة موجودة | الاختبار، مجموعات البيانات الصغيرة |
| periodic | Stream.periodic(duration, fn) |
توليد مؤقت | المؤقتات، الاقتراع |
| StreamController | StreamController<T>() |
إضافته يدوياً | مصادر الأحداث، البيانات في الوقت الفعلي |
| empty | Stream.empty() |
لا شيء | Stream فارغ |
| value | Stream.value(v) |
قيمة واحدة | تغليف قيمة واحدة |
5. عوامل Stream
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: where — التصفية
import 'dart:async';
void main() async {
final amounts = Stream.fromIterable([1500.0, 50.0, 3200.0, 890.0, -100.0]);
// تصفية المبالغ الموجبة فقط >= 100
final highValue = amounts.where((a) => a >= 100);
await for (final amount in highValue) {
print('\$${amount.toStringAsFixed(2)} USD');
}
// الإخراج: $1500.00 USD, $3200.00 USD, $890.00 USD
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: map — التحويل
import 'dart:async';
void main() async {
final amounts = Stream.fromIterable([1500.0, 3200.0, 890.0]);
// تحويل المبالغ إلى سلاسل منسقة
final formatted = amounts.map((a) => '\$${a.toStringAsFixed(2)} USD');
await for (final text in formatted) {
print(text);
}
// الإخراج: $1500.00 USD, $3200.00 USD, $890.00 USD
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: expand — التسطيح
import 'dart:async';
void main() async {
final orders = Stream.fromIterable([
{'id': 'ORD-001', 'items': ['Laptop', 'Mouse']},
{'id': 'ORD-002', 'items': ['Keyboard']},
]);
// expand: كل طلب ← عناصر متعددة
final items = orders.expand((order) =>
(order['items'] as List).cast<String>());
await for (final item in items) {
print('Item: $item');
}
// الإخراج: Item: Laptop, Item: Mouse, Item: Keyboard
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: take / skip / distinct
import 'dart:async';
void main() async {
final data = Stream.fromIterable([1, 1, 2, 2, 3, 3, 4, 5]);
// خذ أول 3 عناصر
print('take(3):');
await data.take(3).forEach(print); // 1, 1, 2
// تخطي أول 2
print('skip(2):');
await Stream.fromIterable([1, 1, 2, 2, 3]).skip(2).forEach(print); // 2, 2, 3
// إزالة التكرارات المتتالية
print('distinct:');
await Stream.fromIterable([1, 1, 2, 2, 3, 3]).distinct().forEach(print); // 1, 2, 3
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
| العامل | الوظيفة | نوع الإرجاع |
|---|---|---|
where |
تصفية العناصر | Stream<T> |
map |
تحويل العناصر | Stream<R> |
expand |
تسطيح من واحد إلى متعدد | Stream<T> |
take |
أخذ أول N عنصر | Stream<T> |
skip |
تخطي أول N عنصر | Stream<T> |
distinct |
إزالة التكرارات المتتالية | Stream<T> |
takeWhile |
الأخذ أثناء تحقق الشرط | Stream<T> |
skipWhile |
التخطي أثناء تحقق الشرط | Stream<T> |
6. StreamController و StreamSubscription
(1) StreamController
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: استخدام StreamController الكامل
import 'dart:async';
class OrderStream {
final _controller = StreamController<Map<String, dynamic>>();
Stream<Map<String, dynamic>> get stream => _controller.stream;
void addOrder(Map<String, dynamic> order) => _controller.add(order);
void addError(Object error) => _controller.addError(error);
void close() => _controller.close();
}
void main() async {
final orderStream = OrderStream();
// الاشتراك في الـ stream
final subscription = orderStream.stream.listen(
(order) => print('Processing: ${order['id']}'),
onError: (e) => print('Error: $e'),
onDone: () => print('Stream closed'),
);
// إضافة الطلبات
orderStream.addOrder({'id': 'ORD-001', 'amount': 1500.0});
orderStream.addOrder({'id': 'ORD-002', 'amount': 3200.0});
orderStream.addOrder({'id': 'ORD-003', 'amount': 890.0});
// إغلاق الـ stream
orderStream.close();
// انتظار انتهاء الـ stream
await subscription.asFuture();
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
(2) بث StreamController
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: وضع البث
import 'dart:async';
void main() async {
// controller بث - مستمعون متعددون
final controller = StreamController<String>.broadcast();
// مشتركون متعددون
final sub1 = controller.stream.listen((e) => print('Sub1: $e'));
final sub2 = controller.stream.listen((e) => print('Sub2: $e'));
// كلا المستمعين يتلقيان نفس الحدث
controller.add('ORD-001');
controller.add('ORD-002');
controller.close();
await Future.delayed(const Duration(milliseconds: 100));
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
7. سيناريو بوب: معالجة تدفق الطلبات في الوقت الفعلي
▶ مثال
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: خط أنابيب Stream لمعالجة الطلبات
import 'dart:async';
class Order {
final String id;
final double amount;
final String status;
final String category;
Order({required this.id, required this.amount, required this.status, required this.category});
@override
String toString() => 'Order($id, \$${amount.toStringAsFixed(2)}, $status, $category)';
}
void main() async {
// محاكاة stream الطلبات في الوقت الفعلي
final controller = StreamController<Order>();
// بناء خط أنابيب المعالجة
final revenueByCategory = <String, double>{};
var totalOrders = 0;
var completedOrders = 0;
controller.stream
.where((order) => order.amount > 0) // تصفية غير الصالح
.where((order) => order.status == 'completed') // المكتملة فقط
.map((order) => order) // يمكن التحويل هنا
.listen(
(order) {
completedOrders++;
totalOrders++;
revenueByCategory.update(
order.category,
(v) => v + order.amount,
ifAbsent: () => order.amount,
);
print(' Processed: ${order.id} - \$${order.amount.toStringAsFixed(2)} USD');
},
onDone: () {
print('\n=== Stream Processing Complete ===');
print('Completed orders: $completedOrders');
for (final entry in revenueByCategory.entries) {
print(' ${entry.key}: \$${entry.value.toStringAsFixed(2)} USD');
}
final total = revenueByCategory.values.fold(0.0, (a, b) => a + b);
print('Total revenue: \$${total.toStringAsFixed(2)} USD');
},
);
// محاكاة الطلبات الواردة
controller.add(Order(id: 'ORD-001', amount: 1500.0, status: 'completed', category: 'Electronics'));
controller.add(Order(id: 'ORD-002', amount: -50.0, status: 'completed', category: 'Books')); // غير صالح
controller.add(Order(id: 'ORD-003', amount: 3200.0, status: 'pending', category: 'Electronics')); // ليس مكتمل
controller.add(Order(id: 'ORD-004', amount: 890.0, status: 'completed', category: 'Clothing'));
controller.add(Order(id: 'ORD-005', amount: 2100.0, status: 'completed', category: 'Electronics'));
controller.close();
await Future.delayed(const Duration(milliseconds: 100));
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
8. المثال الكامل: خط أنابيب Stream لخط أنابيب البيانات
// ============================================
// خط أنابيب معالجة Stream لخط أنابيب البيانات
// stream طلبات في الوقت الفعلي مع عوامل
// ============================================
import 'dart:async';
class Order {
final String id;
final double amount;
final String status;
final String category;
final String region;
const Order({
required this.id,
required this.amount,
required this.status,
required this.category,
this.region = 'US',
});
double get taxAmount => amount * 0.08;
double get totalWithTax => amount + taxAmount;
@override
String toString() =>
'Order($id, \$${amount.toStringAsFixed(2)}, $status, $category, $region)';
}
class StreamPipeline {
final _controller = StreamController<Order>();
final Map<String, double> _revenue = {};
final Map<String, int> _count = {};
int _totalProcessed = 0;
int _totalSkipped = 0;
late StreamSubscription<Order> _subscription;
Stream<Order> get stream => _controller.stream;
StreamPipeline() {
_subscription = _controller.stream
.where((o) => o.amount > 0)
.where((o) => o.status != 'cancelled')
.distinct((o) => o.id) // إزالة التكرار حسب المعرف
.listen(
_processOrder,
onError: (e) => print('Pipeline error: $e'),
onDone: _printSummary,
);
}
void _processOrder(Order order) {
_totalProcessed++;
_revenue.update(
order.category,
(v) => v + order.totalWithTax,
ifAbsent: () => order.totalWithTax,
);
_count.update(order.category, (v) => v + 1, ifAbsent: () => 1);
}
void addOrder(Order order) => _controller.add(order);
void addError(Object error) => _controller.addError(error);
Future<void> close() async {
await _controller.close();
await _subscription.asFuture();
}
void _printSummary() {
final totalRevenue = _revenue.values.fold(0.0, (a, b) => a + b);
final totalCount = _count.values.fold(0, (a, b) => a + b);
print('\n=== DataPipeline Stream Report ===');
print('Processed: $_totalProcessed orders');
print('Skipped: $_totalSkipped records');
print('Revenue: \$${totalRevenue.toStringAsFixed(2)} USD');
print('Orders: $totalCount');
print('\n--- By Category ---');
final sorted = _revenue.entries.toList()
..sort((a, b) => b.value.compareTo(a.value));
for (final entry in sorted) {
final count = _count[entry.key] ?? 0;
final avg = entry.value / count;
print(' ${entry.key}:');
print(' Orders: $count');
print(' Revenue: \$${entry.value.toStringAsFixed(2)} USD');
print(' Average: \$${avg.toStringAsFixed(2)} USD');
}
}
}
void main() async {
final pipeline = StreamPipeline();
// محاكاة stream الطلبات في الوقت الفعلي
final orders = [
Order(id: 'ORD-001', amount: 1500.0, status: 'completed', category: 'Electronics'),
Order(id: 'ORD-002', amount: -50.0, status: 'completed', category: 'Books'),
Order(id: 'ORD-003', amount: 3200.0, status: 'pending', category: 'Electronics'),
Order(id: 'ORD-004', amount: 890.0, status: 'completed', category: 'Clothing'),
Order(id: 'ORD-001', amount: 1500.0, status: 'completed', category: 'Electronics'), // مكرر
Order(id: 'ORD-005', amount: 2100.0, status: 'completed', category: 'Electronics'),
Order(id: 'ORD-006', amount: 500.0, status: 'cancelled', category: 'Books'),
Order(id: 'ORD-007', amount: 120.0, status: 'completed', category: 'Books'),
];
// إصدار الطلبات واحداً تلو الآخر (محاكاة الوقت الفعلي)
for (final order in orders) {
pipeline.addOrder(order);
}
await pipeline.close();
}
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
الإخراج:
=== DataPipeline Stream Report ===
Processed: 5 orders
Skipped: 0 records
Revenue: $8154.00 USD
Orders: 5
--- By Category ---
Electronics:
Orders: 3
Revenue: $7236.00 USD
Average: $2412.00 USD
Clothing:
Orders: 1
Revenue: $961.20 USD
Average: $961.20 USD
Books:
Orders: 1
Revenue: $129.60 USD
Average: $129.60 USD
❓ أسئلة شائعة
س: ما الفرق بين Stream و Future؟ ج: يمثل Future نتيجة غير متزامنة واحدة (0 أو 1 قيمة)، بينما يمثل Stream سلسلة من الأحداث غير المتزامنة (0 إلى قيم كثيرة). Stream هو تعميم لـ Future — نسخة متعددة القيم.
س: هل يمكن الاستماع إلى Stream باشتراك أحادي عدة مرات؟ ج: لا. يمكن الاستماع إلى Stream باشتراك أحادي مرة واحدة فقط؛ الاستماع الثاني سيُلقي StateError. استخدم Stream بث (عبر
asBroadcastStream()أوStreamController.broadcast()) عندما تكون هناك حاجة لمستمعين متعددين.
س: هل عوامل Stream كسولة؟ ج: نعم. عوامل مثل map/where لا تنفذ على الفور؛ إنها تبدأ المعالجة فقط عند الاستماع. يُسمى هذا "stream بارد".
س: كيف تتعامل مع الأخطاء في Stream؟ ج: هناك ثلاث طرق: استدعاء onError في listen، أو عامل handleError، أو تغليف
await forبـ try-catch. يُنصح باستخدام استدعاء onError في listen.
س: هل يحتاج StreamController إلى إغلاق؟ ج: نعم. استدعِ controller.close() لإغلاق الـ stream وإخطار المستمعين بأن الـ stream قد انتهى. عدم إغلاقه سيتسبب في انتظار المستمعين إلى ما لا نهاية.
س: ما هي قيود Stream البث؟ ج: لا يدعم Stream البث الإيقاف المؤقت/الاستئناف، وإذا اشترك مستمع بعد إصدار حدث ما، فإنه سيفوت الأحداث السابقة. مناسب لسيناريوهات "الاشتراك في الوقت الفعلي".
س: هل يدعم Stream الضغط العكسي؟ ج: يدعم Stream باشتراك أحادي الضغط العكسي بشكل طبيعي — عندما يعالج المستمع (المستهلك) ببطء، سينتظر المنتج. لا يدعم Stream البث الضغط العكسي.
📖 ملخص
- Stream هو سلسلة من الأحداث غير المتزامنة، مقسمة إلى اشتراك أحادي (مستمع واحد) وبث (مستمعون متعددون)
- طرق الإنشاء: fromIterable (بيانات موجودة)، periodic (توليد مؤقت)، StreamController (تحكم يدوي)
- سلسلة العوامل: where تصفية ← map تحويل ← expand تسطيح ← take/skip حد ← distinct إزالة تكرار
- StreamController هو نهاية الإنتاج لـ Stream، بينما StreamSubscription هو نهاية الاستهلاك
- يتيح خط أنابيب Stream معالجة ملايين قطع البيانات واحدة تلو الأخرى، مع استخدام ذاكرة مستقر ودعم المعالجة في الوقت الفعلي
📝 تمارين
- أساسي (صعوبة ⭐): استخدم
Stream.fromIterableلإنشاء stream يحتوي على 10 مبالغ، استخدمwhereلتصفية تلك الأكبر من 500، وmapلتحويلها إلى تنسيق الدولار الأمريكي، وlistenلطباعة النتائج. - متوسط (صعوبة ⭐⭐): استخدم
StreamControllerلمحاكاة stream طلبات في الوقت الفعلي، مع إضافة طلب واحد في الثانية لمدة 5 ثوانٍ. ابنِ خط أنابيب لتصفية الطلبات المكتملة، وتجميع الإيرادات حسب الفئة، وأخيراً إخراج تقرير. - تحدي (صعوبة ⭐⭐⭐): نفّذ دالة "دمج streams" تجمع بين streamَي طلبات في واحد (متشابك زمنياً)، وتزيل تكرارهما، ثم تعالجهما. تلميح: استخدم
StreamGroup(من حزمةasync) أو ادمج يدوياً باستخدامStreamController.