Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

أساسيات الـ Streams

جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 77 من 110.

بينما يقدم Future قيمة واحدة، يقدم Stream سلسلة من القيم بمرور الوقت. فكر فيه كأنه أنبوب يمكنه إرسال قطع متعددة من البيانات - وهو مثالي للأحداث، أو التحديثات في الوقت الفعلي، أو معالجة البيانات قطعة بقطعة.

يمكنك إنشاء تدفق (stream) بسيط باستخدام Stream.fromIterable() أو دالة مولد غير متزامنة باستخدام async* و yield:

Stream<int> countToThree() async* {
  yield 1;
  yield 2;
  yield 3;
}

Future<void> main() async {
  await for (var number in countToThree()) {
    print(number);
  }
}
// المخرجات: 1, 2, 3

تحدد الكلمة الأساسية async* دالة تُرجع Stream، وتقوم yield بإصدار كل قيمة. لاستهلاك الـ stream، استخدم await for التي تعالج كل قيمة فور وصولها.

يمكنك أيضاً الاستماع إلى دفق (stream) باستخدام التابع listen()، والذي يأخذ دالة استدعاء (callback function):

Stream<String> greetings() async* {
  yield 'Hello';
  yield 'Hi';
  yield 'Hey';
}

void main() {
  greetings().listen((message) {
    print(message);
  });
}

الفرق الجوهري عن Futures: يكتمل Future مرة واحدة بقيمة واحدة، بينما يمكن لـ Stream إرسال قيم متعددة قبل أن ينتهي. وهذا يجعل Streams مثالية للتعامل مع البيانات المستمرة مثل تفاعلات المستخدم، أو قراءات المستشعرات، أو البيانات التي تصل في أجزاء.

challenge icon

التحدي

سهل

لنقم ببناء نظام مؤقت تنازلي يرسل القيم بمرور الوقت باستخدام الـ streams! ستقوم بإنشاء فئة (class) تولد تسلسلاً من أرقام العد التنازلي، مما يوضح كيف تقوم الـ streams بتقديم قيم متعددة بدلاً من قيمة واحدة فقط.

ستقوم بتنظيم الكود الخاص بك في ملفين:

  • countdown.dart: أنشئ فئة Countdown التي تولد streams للعد التنازلي. يجب أن تحتوي الفئة الخاصة بك على:
    • حقل start من نوع (int) يخزن رقم البداية للعد التنازلي
    • مشد (constructor) يأخذ رقم البداية
    • دالة countDown() تعيد Stream<int>. استخدم async* و yield لإرسال الأرقام من start نزولاً إلى 0 (متضمناً الصفر)
    • دالة countDownWithMessage() تعيد Stream<String>. يجب أن ترسل هذه الدالة سلاسل نصية بتنسيق 'T-minus [number]' لكل رقم من start نزولاً إلى 1، ثم ترسل 'Liftoff!' كقيمة نهائية
  • main.dart: قم باستيراد ملف العد التنازلي الخاص بك واستعرض كلتا دالتي الـ stream. يجب أن تكون الدالة الرئيسية (main function) من نوع async وتقوم بما يلي:
    • إنشاء مثيل (instance) من Countdown يبدأ من 3
    • طباعة Number countdown:
    • استخدام await for للتكرار عبر countDown() وطباعة كل رقم
    • طباعة سطر فارغ
    • طباعة Launch sequence:
    • استخدام await for للتكرار عبر countDownWithMessage() وطباعة كل رسالة

لاحظ كيف تقوم كل عبارة yield بإرسال قيمة عبر الـ stream، وكيف تقوم await for بمعالجة كل قيمة فور وصولها. على عكس الـ Future الذي يقدم نتيجة واحدة، ستقوم الـ streams الخاصة بك بإرسال قيم متعددة بالتتابع!

المخرجات المتوقعة:

Number countdown:
3
2
1
0

Launch sequence:
T-minus 3
T-minus 2
T-minus 1
Liftoff!

ورقة مرجعية

يوفر الـ Stream سلسلة من القيم بمرور الوقت، على عكس الـ Future الذي يوفر قيمة واحدة فقط. تعد الـ Streams مثالية للأحداث، أو التحديثات في الوقت الفعلي، أو معالجة البيانات قطعة بقطعة.

قم بإنشاء stream باستخدام دالة مولد غير متزامنة (async generator function) مع async* و yield:

Stream<int> countToThree() async* {
  yield 1;
  yield 2;
  yield 3;
}

استهلك الـ stream باستخدام await for:

Future<void> main() async {
  await for (var number in countToThree()) {
    print(number);
  }
}

بدلاً من ذلك، استخدم التابع listen() مع دالة استدعاء (callback):

void main() {
  greetings().listen((message) {
    print(message);
  });
}

يمكنك أيضاً إنشاء stream من iterable باستخدام Stream.fromIterable().

جرّب بنفسك

import 'countdown.dart';

Future<void> main() async {
  // TODO: قم بإنشاء مثيل Countdown يبدأ من 3
  
  // TODO: اطبع 'Number countdown:'
  
  // TODO: استخدم await for للتكرار عبر countDown() وطباعة كل رقم
  
  // TODO: اطبع سطرًا فارغًا
  
  // TODO: اطبع 'Launch sequence:'
  
  // TODO: استخدم await for للتكرار عبر countDownWithMessage() وطباعة كل رسالة
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming