Dart: Stream في Dart

آخر تحديث: 2026-08-26

Stream هو نهر من البيانات — مستمر، تتم معالجته فور وصوله، لا حاجة للانتظار حتى وصول كل شيء دفعة واحدة.

1. ما ستتعلمه


2. قصة مطور حقيقي

(1) نقطة الألم: ملايين سجلات البيانات لا يمكن تحميلها في الذاكرة دفعة واحدة

كان خط أنابيب البيانات الخاص ببوب يقوم في البداية بتحميل جميع الـ 1,200,000 طلب في الذاكرة للمعالجة عند التعامل مع طلبات التجارة الإلكترونية، مما أدى إلى ذروة ذاكرة 4 جيجابايت وتسبب في تحطم الخادم بخطأ OOM ثلاث مرات. علاوة على ذلك، مع استمرار وصول الطلبات في الوقت الفعلي، كان نموذج المعالجة الدفعية غير قادر على التعامل مع البيانات الواردة حديثاً.

(2) حل Stream

يسمح Stream بمعالجة البيانات قطعة قطعة مثل تدفق المياه: عالج واحدة فور وصولها، مع إبقاء استخدام الذاكرة مستقراً عند 50 ميجابايت. عوامل Stream (where/map/reduce) تتيح التعريف التصريحي لخط أنابيب المعالجة.

DART
orderStream
  .where((order) => order.status == 'completed')
  .map((order) => order.amount)
  .fold(0, (sum, amount) => sum + amount)
  .then((total) => print('Revenue: \$$total USD'));
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

(3) الفوائد


3. أساسيات Stream

(1) الاشتراك الأحادي مقابل البث

100%
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
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
النوع المشتركون إعادة التشغيل حالة الاستخدام
Stream باشتراك أحادي 1 غير قابل لإعادة التشغيل قراءة الملفات، استجابات HTTP
Stream بث متعدد غير قابل لإعادة التشغيل أحداث واجهة المستخدم، البيانات في الوقت الفعلي

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: أساسيات Stream

DART
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();
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

4. إنشاء Stream

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: إنشاء من fromIterable

DART
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');
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: إنشاء من periodic

DART
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);
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: إنشاء من StreamController

DART
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');
  }
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في 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

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: where — التصفية

DART
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
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: map — التحويل

DART
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
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: expand — التسطيح

DART
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
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: take / skip / distinct

DART
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
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في 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

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: استخدام StreamController الكامل

DART
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();
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

(2) بث StreamController

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: وضع البث

DART
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));
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

7. سيناريو بوب: معالجة تدفق الطلبات في الوقت الفعلي

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

: خط أنابيب Stream لمعالجة الطلبات

DART
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));
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

8. المثال الكامل: خط أنابيب Stream لخط أنابيب البيانات

DART
// ============================================
// خط أنابيب معالجة 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();
}
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل محلياً في DartPad أو عبر `dart run`. جميع الأمثلة في دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.

الإخراج:

TEXT 📖 للعرض فقط
=== 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 البث الضغط العكسي.


📖 ملخص


📝 تمارين

  1. أساسي (صعوبة ⭐): استخدم Stream.fromIterable لإنشاء stream يحتوي على 10 مبالغ، استخدم where لتصفية تلك الأكبر من 500، و map لتحويلها إلى تنسيق الدولار الأمريكي، و listen لطباعة النتائج.
  2. متوسط (صعوبة ⭐⭐): استخدم StreamController لمحاكاة stream طلبات في الوقت الفعلي، مع إضافة طلب واحد في الثانية لمدة 5 ثوانٍ. ابنِ خط أنابيب لتصفية الطلبات المكتملة، وتجميع الإيرادات حسب الفئة، وأخيراً إخراج تقرير.
  3. تحدي (صعوبة ⭐⭐⭐): نفّذ دالة "دمج streams" تجمع بين streamَي طلبات في واحد (متشابك زمنياً)، وتزيل تكرارهما، ثم تعالجهما. تلميح: استخدم StreamGroup (من حزمة async) أو ادمج يدوياً باستخدام StreamController.

← الدرس السابق | الدرس التالي →

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%