Dart: البرمجة غير المتزامنة في Dart
آخر تحديث: 2026-08-26
البرمجة غير المتزامنة تتيح لبرنامجك عدم الانتظار — عملية I/O مدتها 3 ثوانٍ تتيح للـ CPU القيام بعمل آخر بدلاً من الانتظار فقط.
1. ما ستتعلمه
- دورة حياة Future: قيد الانتظار / مكتمل / فاشل
- async / await: السكر النحوي ومعالجة الأخطاء
- تكوين Future: Future.wait / Future.any / Future.forEach
- Completer: التحكم اليدوي في إكمال Future
- سيناريو بوب: خط أنابيب البيانات يقدم طلبات متزامنة إلى واجهات API متعددة للتجارة الإلكترونية
2. قصة مطور حقيقي
(1) نقطة الألم: الطلبات المتسلسلة تسبب تحميل صفحة مدته 12 ثانية
يحتاج خط أنابيب البيانات الخاص ببوب إلى جلب البيانات من 3 واجهات API: الطلبات (3 ثوانٍ)، المنتجات (2 ثانية)، والعملاء (2 ثانية). استخدم في البداية طلبات متسلسلة: 3 + 2 + 2 = 7 ثوانٍ. بإضافة استعلام قاعدة البيانات (5 ثوانٍ)، استغرق إنشاء التقرير بالكامل 12 ثانية. كانت تجربة المستخدم سيئة، وشكا عملاء SaaS من أنها "بطيئة جداً".
(2) الحل: التنفيذ المتزامن مع Future.wait
استخدام Future.wait يجعل طلبات API الثلاثة تعمل بشكل متزامن، حيث يُحدد الوقت الإجمالي بواسطة الأبطأ: 3 ثوانٍ. مع استعلامات قاعدة البيانات المتزامنة، يتم تقصير إنشاء التقرير بالكامل إلى 4 ثوانٍ.
// متسلسل: 3 + 2 + 2 = 7 ثوانٍ
final orders = await fetchOrders(); // 3s
final products = await fetchProducts(); // 2s
final customers = await fetchCustomers(); // 2s
// متزامن: max(3, 2, 2) = 3 ثوانٍ
final results = await Future.wait([
fetchOrders(),
fetchProducts(),
fetchCustomers(),
]);
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
(3) الفوائد
- التنفيذ المتزامن لـ Future.wait يقلل استدعاءات API من 7 ثوانٍ إلى 3 ثوانٍ، الإجمالي 4 ثوانٍ.
- async/await يجعل الكود غير المتزامن يبدو مثل الكود المتزامن، مما يحسن قابلية القراءة.
- معالجة الأخطاء القوية تضمن أن استثناءات الشبكة لم تعد تتسبب في تحطم البرنامج.
3. أساسيات Future
(1) دورة حياة Future
sequenceDiagram participant بوب participant API1 participant API2 participant API3 بوب->>API1: fetchOrders() بوب->>API2: fetchProducts() بوب->>API3: fetchCustomers() Note over بوب: Future.wait متزامن التنفيذ API1-->>بوب: 1.2 مليون طلب API2-->>بوب: 500K منتج API3-->>بوب: 300K عميل بوب->>بوب: دمج وتحليل
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: إنشاء واستخدام Future
import 'dart:async';
// إنشاء Future يكتمل بعد تأخير
Future<String> fetchOrder() async {
await Future.delayed(const Duration(seconds: 2));
return 'ORD-001: \$1500.00 USD';
}
// Future مع خطأ
Future<String> fetchOrderWithRetry() {
return Future.delayed(const Duration(seconds: 1), () {
throw Exception('Network timeout');
});
}
void main() async {
// قيد الانتظار ← مكتمل
print('Fetching order...');
final order = await fetchOrder();
print(order);
// قيد الانتظار ← فاشل
try {
await fetchOrderWithRetry();
} catch (e) {
print('Error: $e');
}
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
| حالة Future | المعنى |
|---|---|
| قيد الانتظار (pending) | غير مكتمل، في انتظار |
| مكتمل بقيمة (completed with value) | مكتمل بنجاح، يحمل قيمة |
| مكتمل بخطأ (completed with error) | مكتمل بفشل، يحمل استثناءً |
4. غير متزامن / انتظار بعمق
(1) الصياغة الأساسية
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: أساسيات غير متزامن/انتظار
import 'dart:async';
Future<double> calculateOrderTotal(String orderId) async {
// await يوقف التنفيذ حتى يكتمل Future
final amount = await fetchAmount(orderId);
final taxRate = await fetchTaxRate(orderId);
return amount * (1 + taxRate);
}
Future<double> fetchAmount(String orderId) async {
await Future.delayed(const Duration(milliseconds: 500));
return 1500.0;
}
Future<double> fetchTaxRate(String orderId) async {
await Future.delayed(const Duration(milliseconds: 300));
return 0.08;
}
void main() async {
final total = await calculateOrderTotal('ORD-001');
print('Total: \$${total.toStringAsFixed(2)} USD');
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
(2) معالجة الأخطاء
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: معالجة الأخطاء في غير متزامن/انتظار
import 'dart:async';
Future<String> fetchApiData(String endpoint) async {
await Future.delayed(const Duration(seconds: 1));
if (endpoint.contains('invalid')) {
throw Exception('API error: $endpoint not found');
}
return 'Data from $endpoint';
}
Future<void> robustFetch(String endpoint) async {
try {
final data = await fetchApiData(endpoint);
print('Success: $data');
} on Exception catch (e) {
print('Exception: $e');
} finally {
print('Fetch completed for $endpoint');
}
}
void main() async {
await robustFetch('orders'); // Success
await robustFetch('invalid-endpoint'); // Exception
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
| طريقة معالجة الأخطاء | الصيغة | حالة الاستخدام |
|---|---|---|
| try-catch | try { await f(); } catch (e) {} |
عند الحاجة للاسترداد |
| catchError | f().catchError((e) => ...) |
النمط الوظيفي |
| onError | f().then(..., onError: ...) |
استدعاءات بسيطة |
5. تكوين Future
(1) Future.wait — الانتظار المتزامن
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: Future.wait المتزامن
import 'dart:async';
Future<List<String>> fetchOrders() async {
await Future.delayed(const Duration(seconds: 3));
return ['ORD-001', 'ORD-002', 'ORD-003'];
}
Future<List<String>> fetchProducts() async {
await Future.delayed(const Duration(seconds: 2));
return ['Laptop', 'Mouse', 'Keyboard'];
}
Future<List<String>> fetchCustomers() async {
await Future.delayed(const Duration(seconds: 2));
return ['Alice', 'Bob', 'Charlie'];
}
void main() async {
// متزامن: max(3, 2, 2) = ~3 ثوانٍ
final stopwatch = Stopwatch()..start();
final results = await Future.wait([
fetchOrders(),
fetchProducts(),
fetchCustomers(),
]);
stopwatch.stop();
print('Orders: ${results[0]}');
print('Products: ${results[1]}');
print('Customers: ${results[2]}');
print('Time: ${stopwatch.elapsedMilliseconds}ms');
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: معالجة أخطاء Future.wait
import 'dart:async';
Future<String> riskyFetch(String name, bool shouldFail) async {
await Future.delayed(const Duration(seconds: 1));
if (shouldFail) throw Exception('$name failed');
return '$name data';
}
void main() async {
// Future.wait يفشل بسرعة - إذا فشل أي منها، يفشل الكل
try {
await Future.wait([
riskyFetch('API-1', false),
riskyFetch('API-2', true), // هذا يفشل
riskyFetch('API-3', false),
]);
} catch (e) {
print('Future.wait failed: $e');
}
// الحفاظ على النتائج الفردية مع eagerError: false
final results = await Future.wait(
[
riskyFetch('API-1', false).then((v) => Result.success(v)),
riskyFetch('API-2', true).then((v) => Result.success(v)).catchError((e) => Result.failure(e.toString())),
riskyFetch('API-3', false).then((v) => Result.success(v)),
],
);
for (final r in results) {
print(r.isSuccess ? 'OK: ${r.data}' : 'FAIL: ${r.error}');
}
}
class Result<T> {
final T? data;
final String? error;
final bool isSuccess;
Result.success(this.data) : error = null, isSuccess = true;
Result.failure(this.error) : data = null, isSuccess = false;
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
(2) Future.any — السباق
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: سباق Future.any
import 'dart:async';
Future<String> fetchFromCache() async {
await Future.delayed(const Duration(milliseconds: 100));
return 'Cache: ORD-001 data';
}
Future<String> fetchFromApi() async {
await Future.delayed(const Duration(seconds: 2));
return 'API: ORD-001 data';
}
Future<String> fetchFromDb() async {
await Future.delayed(const Duration(milliseconds: 500));
return 'DB: ORD-001 data';
}
void main() async {
// يُرجع الأول الذي يكتمل
final fastest = await Future.any([
fetchFromCache(),
fetchFromApi(),
fetchFromDb(),
]);
print('Fastest: $fastest'); // Cache: ORD-001 data
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
(3) Future.forEach — التكرار المتسلسل
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: Future.forEach
import 'dart:async';
Future<void> processOrder(String orderId) async {
await Future.delayed(const Duration(milliseconds: 500));
print('Processed: $orderId');
}
void main() async {
final orders = ['ORD-001', 'ORD-002', 'ORD-003'];
// المعالجة المتسلسلة
await Future.forEach(orders, processOrder);
print('All orders processed');
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
| طريقة التكوين | السلوك | التزامن | حالة الاستخدام |
|---|---|---|---|
Future.wait |
انتظار الكل | متزامن | طلبات الدفعات |
Future.any |
الأول في الإكمال | متزامن | السباق / البديل |
Future.forEach |
الإكمال المتسلسل | متسلسل | العمليات المعتمدة على الترتيب |
6. التحكم اليدوي بـ Completer
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: Completer
import 'dart:async';
// التحكم اليدوي بـ Future باستخدام Completer
class ApiService {
final Completer<String> _initCompleter = Completer<String>();
Future<String> get initialized => _initCompleter.future;
void onConnected(String serverInfo) {
if (!_initCompleter.isCompleted) {
_initCompleter.complete(serverInfo);
}
}
void onError(Object error) {
if (!_initCompleter.isCompleted) {
_initCompleter.completeError(error);
}
}
}
void main() async {
final service = ApiService();
// محاكاة التهيئة غير المتزامنة
Future.delayed(const Duration(seconds: 1), () {
service.onConnected('Server v3.0.1, 1,000,000 records');
});
print('Waiting for initialization...');
final info = await service.initialized;
print('Connected: $info');
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
7. سيناريو بوب: طلبات API متزامنة
▶ مثال
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
: جلب البيانات المتزامن لخط أنابيب البيانات
import 'dart:async';
// استدعاءات API محاكاة
Future<List<Map<String, dynamic>>> fetchOrders() async {
await Future.delayed(const Duration(seconds: 2));
return [
{'id': 'ORD-001', 'amount': 1500.0, 'category': 'Electronics'},
{'id': 'ORD-002', 'amount': 3200.0, 'category': 'Electronics'},
{'id': 'ORD-003', 'amount': 890.0, 'category': 'Clothing'},
];
}
Future<Map<String, double>> fetchProductPrices() async {
await Future.delayed(const Duration(seconds: 1));
return {'Laptop': 1299.99, 'Mouse': 29.99, 'Keyboard': 79.99};
}
Future<List<String>> fetchCustomerNames() async {
await Future.delayed(const Duration(seconds: 1));
return ['Alice', 'Bob', 'Charlie'];
}
// جلب البيانات المتزامن مع معالجة الأخطاء
Future<void> generateReport() async {
final stopwatch = Stopwatch()..start();
try {
// جلب جميع البيانات بشكل متزامن
final results = await Future.wait([
fetchOrders().then((v) => ('orders', v)).catchError((e) => ('orders', null)),
fetchProductPrices().then((v) => ('products', v)).catchError((e) => ('products', null)),
fetchCustomerNames().then((v) => ('customers', v)).catchError((e) => ('customers', null)),
]);
stopwatch.stop();
print('=== DataPipeline Report ===');
print('Fetch time: ${stopwatch.elapsedMilliseconds}ms');
for (final (key, value) in results) {
if (value != null) {
print('$key: OK (${value is List ? value.length : value.length} items)');
} else {
print('$key: FAILED');
}
}
} catch (e) {
print('Report generation failed: $e');
}
}
void main() async {
await generateReport();
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
8. المثال الكامل: معالجة البيانات غير المتزامنة لخط أنابيب البيانات
// ============================================
// معالجة البيانات غير المتزامنة لخط أنابيب البيانات
// Future وغير متزامن/انتظار والعمليات المتزامنة
// ============================================
import 'dart:async';
// مصادر البيانات المحاكاة
Future<List<Map<String, dynamic>>> fetchOrders({int delay = 2}) async {
await Future.delayed(Duration(seconds: delay));
return [
{'id': 'ORD-001', 'amount': 1500.0, 'status': 'completed', 'category': 'Electronics'},
{'id': 'ORD-002', 'amount': 50.0, 'status': 'completed', 'category': 'Books'},
{'id': 'ORD-003', 'amount': 3200.0, 'status': 'pending', 'category': 'Electronics'},
{'id': 'ORD-004', 'amount': 890.0, 'status': 'completed', 'category': 'Clothing'},
];
}
Future<List<Map<String, dynamic>>> fetchProducts({int delay = 1}) async {
await Future.delayed(Duration(seconds: delay));
return [
{'name': 'Laptop', 'price': 1299.99, 'category': 'Electronics'},
{'name': 'Mouse', 'price': 29.99, 'category': 'Electronics'},
{'name': 'Novel', 'price': 12.99, 'category': 'Books'},
];
}
Future<double> fetchTaxRate(String region) async {
await Future.delayed(const Duration(milliseconds: 500));
return switch (region) {
'US' => 0.08,
'EU' => 0.20,
'UK' => 0.15,
_ => 0.10,
};
}
// خط أنابيب غير متزامن مع عمليات متزامنة
class AsyncPipeline {
final String name;
String status = 'idle';
AsyncPipeline({required this.name});
Future<Map<String, dynamic>> run({String region = 'US'}) async {
status = 'running';
final stopwatch = Stopwatch()..start();
try {
// الخطوة 1: جلب البيانات المتزامن
final (orders, products, taxRate) = await (
fetchOrders(),
fetchProducts(),
fetchTaxRate(region),
).wait;
// الخطوة 2: معالجة الطلبات
final completedOrders = orders
.where((o) => o['status'] == 'completed')
.toList();
// الخطوة 3: حساب الإيرادات
final revenue = completedOrders.fold<double>(
0, (sum, o) => sum + (o['amount'] as double));
final taxAmount = revenue * taxRate;
final totalWithTax = revenue + taxAmount;
// الخطوة 4: التجميع حسب الفئة
final byCategory = <String, double>{};
for (final order in completedOrders) {
final cat = order['category'] as String;
final amt = order['amount'] as double;
byCategory.update(cat, (v) => v + amt, ifAbsent: () => amt);
}
stopwatch.stop();
status = 'completed';
return {
'pipeline': name,
'region': region,
'taxRate': taxRate,
'totalOrders': orders.length,
'completedOrders': completedOrders.length,
'revenue': revenue,
'tax': taxAmount,
'totalWithTax': totalWithTax,
'byCategory': byCategory,
'processingTime': stopwatch.elapsedMilliseconds,
'status': status,
};
} catch (e) {
status = 'failed';
rethrow;
}
}
}
void main() async {
final pipeline = AsyncPipeline(name: 'E-Commerce Analytics');
print('=== Starting DataPipeline ===');
final report = await pipeline.run(region: 'US');
print('\n=== Report ===');
print('Pipeline: ${report['pipeline']}');
print('Region: ${report['region']}');
print('Tax Rate: ${(report['taxRate'] as double * 100).toStringAsFixed(1)}%');
print('Total Orders: ${report['totalOrders']}');
print('Completed: ${report['completedOrders']}');
print('Revenue: \$${(report['revenue'] as double).toStringAsFixed(2)} USD');
print('Tax: \$${(report['tax'] as double).toStringAsFixed(2)} USD');
print('Total: \$${(report['totalWithTax'] as double).toStringAsFixed(2)} USD');
print('Time: ${report['processingTime']}ms');
print('\nBy Category:');
for (final entry in (report['byCategory'] as Map<String, double>).entries) {
print(' ${entry.key}: \$${entry.value.toStringAsFixed(2)} USD');
}
}
> **الإخراج:** نفّذ في DartPad أو باستخدام `dart run`. جميع أمثلة دورة Dart مبنية على Dart 3.x / Flutter 3.x. قد تختلف النتائج قليلاً حسب إصدار SDK.
الإخراج:
=== Starting DataPipeline ===
=== Report ===
Pipeline: E-Commerce Analytics
Region: US
Tax Rate: 8.0%
Total Orders: 4
Completed: 3
Revenue: $2440.00 USD
Tax: $195.20 USD
Total: $2635.20 USD
Time: 2000ms
By Category:
Electronics: $1500.00 USD
Books: $50.00 USD
Clothing: $890.00 USD
❓ أسئلة شائعة
س: ما نوع الإرجاع لدالة غير متزامنة؟ ج: دالة غير متزامنة تغلف تلقائياً قيمة الإرجاع في Future. أعلن عن نوع إرجاع
Future<T>، وأعد ببساطة T داخل الدالة.
س: هل يمكن استخدام await فقط في الدوال غير المتزامنة؟ ج: نعم. يمكن استخدام await فقط في الدوال غير المتزامنة أو المولدات async*. يدعم Dart 3.5+ الانتظار على المستوى الأعلى (فقط في سكربتات Dart).
س: ماذا يحدث إذا فشل Future في Future.wait؟ ج: افتراضياً، إذا فشل أي Future، يُلقي Future.wait هذا الاستثناء على الفور (تستمر Futures الأخرى في العمل ولكن يتم تجاهل نتائجها). يمكنك استخدام
eagerError: falseللانتظار حتى يكتمل الكل.
س: ما الفرق بين غير متزامن/انتظار و .then()؟ ج: إنهما متكافئتان وظيفياً، لكن غير متزامن/انتظار أكثر قابلية للقراءة (تدفق خطي)، بينما .then() أكثر وظيفية (تسلسل). للاستخدام اليومي، يُنصح بـ غير متزامن/انتظار؛ .then() مناسب للتحويلات البسيطة.
س: متى أستخدم Completer؟ ج: استخدم Completer عندما تحتاج إلى التحكم يدوياً في توقيت إكمال Future. السيناريوهات الشائعة: تحويل استدعاءات الأحداث إلى Futures، رسائل WebSocket، استدعاءات مكتبات الطرف الثالث. في معظم الحالات، يمكنك فقط استخدام غير متزامن/انتظار.
س: هل Future متعدد الإرسال أم أحادي؟ ج: Future أحادي الإرسال — يمكن استهلاكه بواسطة await واحد أو .then() واحد. للإرسال المتعدد، تحتاج إلى Stream أو asStream().
س: كيف أنفذ التحكم في المهلة؟ ج: استخدم طريقة Future.timeout(). على سبيل المثال:
await fetchApi().timeout(Duration(seconds: 5), onTimeout: () => defaultData).
📖 ملخص
- يمثل Future النتيجة النهائية لعملية حسابية غير متزامنة، بثلاث حالات: قيد الانتظار/مكتمل/فاشل.
- غير متزامن/انتظار هو سكر نحوي لـ Future، مما يجعل الكود غير المتزامن يُقرأ مثل الكود المتزامن.
- Future.wait ينفذ عدة Futures بشكل متزامن، مع تحديد الوقت الإجمالي بواسطة الأبطأ.
- Future.any يتسابق للحصول على الأسرع؛ Future.forEach ينفذ بشكل متسلسل.
- Completer يتحكم يدوياً في إكمال Future، مناسب لتحويل استدعاءات إلى Futures.
📝 تمارين
- أساسي (صعوبة ⭐): اكتب 3 دوال تُرجع Futures (كل منها بتأخير 1/2/3 ثوانٍ). استدعها بشكل متسلسل باستخدام غير متزامن/انتظار وقِس الوقت الإجمالي. ثم استدعها بشكل متزامن باستخدام Future.wait وقارن الأوقات.
- متوسط (صعوبة ⭐⭐): نفّذ دالة طلب غير متزامن مع إعادة المحاولة:
fetchWithRetry(url, retries: 3, backoff: Duration). يجب أن تُعيد المحاولة عند الفشل مع تراجع أُسّي وتُلقي استثناءً بعد تجاوز حد إعادة المحاولة. - تحدي (صعوبة ⭐⭐⭐): نفّذ بروتوكول "طلب-استجابة" بسيط باستخدام Completer: أرسل طلباً وانتظر الاستجابة المقابلة، مع دعم المهلة. محاكاة ناقل رسائل حيث يمكن إرسال طلبات متعددة بشكل متزامن.