Flutter / حدود التطبيق غير المتزامنة / الدرس 7
المستقبلات وهوية النتائج
افصل الانتظار والعمر وحداثة النتائج كي لا يستبدل اكتمال متأخر عملا أحدث بصمت.
في هذه الصفحة
أهداف الدرس
- يمثل Future اكتمالا مستقبليا واحدا
- أنشئ العمل غير المتزامن عند حد مقصود
- راقب مستقبلا مستقرا
يمثل Future اكتمالا مستقبليا واحدا
يحمل Future قيمة مستقبلية واحدة أو فشلا واحدا. يعلّق انتظاره متابعة الدالة غير المتزامنة؛ ولا يجمّد التطبيق ولا ينقل العمل الحسابي تلقائيا إلى isolate آخر. أثناء الانتظار يمكن للمستخدم تعديل الاستعلام أو المغادرة أو بدء عملية أخرى. تغيّر هذه الأحداث مدى صلة النتيجة الأصلية. صِف العملية كانتقال حالة له مالك وهوية مدخل وسياسة اكتمال. إن اعتبار كل Future ناجح إذنا لتحديث الشاشة يتجاهل الأحداث التي وقعت خلال الانتظار.
أنشئ العمل غير المتزامن عند حد مقصود
يراقب FutureBuilder مستقبلا ويعرض بحسب لقطته. لا تزوّده بعملية منشأة حديثا مع كل بناء غير مرتبط إلا إذا كان تكرار البدء مقصودا. احصل على المستقبل عند حد دورة حياة المالك المناسب أو استجابة لتغير مدخل صريح. ثم ميّز الانتظار والخطأ والنجاح ببيانات فارغة والنجاح ببيانات موجودة. يخفي مؤشر التحميل المستعمل لكل الحالات الفشل والفراغ. تدير Flutter جدول استدعاء builder، لذلك يجب أن يخلو العرض من طلبات إضافية وآثار جانبية.
راقب مستقبلا مستقرا
يحمل المقتطف الأول تسمية مصطنعة مرة واحدة طوال عمر State. يهيأ حقل Future مرة واحدة، وتعيد إعادة بناء الأب استعمال العملية المعلقة أو المكتملة نفسها. يوفر builder وصفا للانتظار والخطأ ويقرأ البيانات الناجحة في الفرع المناسب. هذا مقتطف يحتاج إلى بيئة، وليس تسجيلا زمنيا منفذا. حتى المستقبل المكتمل قد ينتج لقطة انتظار عند إعطائه إلى FutureBuilder جديد، إذ لا يمكن معرفة اكتماله تزامنيا عبر هذه الواجهة. ينبغي للاختبار تأكيد الحالات النهائية المفيدة لا عدّ استدعاءات وسطية ثابتة.
late final Future<String> label;
@override void initState() {
super.initState();
label = Future<String>.value('Maps');
}
Widget content() => FutureBuilder<String>(
future: label,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) return const Text('Loading');
if (snapshot.hasError) return const Text('Could not load');
return Text(snapshot.data ?? 'No label');
},
);
The eventual successful label is Maps.
حُذفت State المحيطة والاستيرادات. توفر Future.value بيانات محلية مصطنعة دون شبكة.
احم الحداثة إلى جانب العمر
يزيد المقتطف الثاني رقم جيل مع كل محاولة بحث. لا تعتمد النتيجة إلا إذا بقيت State موجودة وطابقت تذكرتها أحدث جيل. هذه سياسة أحدث نتيجة وليست إلغاء؛ فقد يظل العمل القديم يستهلك الموارد. إذا دعمت الواجهة الإلغاء، فاجمعه مع فحص الهوية. وبالمثل يحد انتهاء المهلة الانتظار لكنه قد لا يوقف العمل الأصلي. قرّر هل يحفظ فشل التحديث النتائج المفيدة السابقة أم يستبدلها بخطأ، وطبّق قاعدة الهوية نفسها على اكتمال الخطأ والنجاح.
int generation = 0;
List<String> results = [];
String? failure;
Future<void> search(String query) async {
final ticket = ++generation;
try {
final next = await repository.search(query);
if (!mounted || ticket != generation) return;
setState(() { results = next; failure = null; });
} catch (_) {
if (!mounted || ticket != generation) return;
setState(() { failure = 'Search failed'; });
}
}
Only the newest search attempt may replace results or failure.
repository اعتماد يحقنه التطبيق. لا يصدر المثال طلبا حقيقيا ولا يدّعي إلغاء النقل.
التقط الخطأ حيث يمكن تقرير التعافي
التقط الخطأ قرب الحد القادر على تحويله إلى نتيجة مفيدة للتطبيق. يجعل الالتقاط العام الذي يعيد قائمة فارغة بصمت الطلب الفاشل مماثلا لبحث فارغ حقيقي. احفظ السياق التشخيصي عبر سياسة التسجيل المراجعة مع عرض رسالة آمنة للمستخدم. ولا تسجل الأسرار أو الحمولات الحساسة كاملة لتشخيص سباق. وإذا غيّرت العملية حالة بعيدة فقد يحتاج الاكتمال غير المؤكد إلى تسوية بدلا من إعادة عمياء، لأن الخادم ربما قبل الأمر بالفعل.
اختبر ترتيب الاكتمال صراحة
استخدم مستودعا مزيفا يمكن إكمال ردوده المعلقة بترتيب تختاره. ابدأ البحث A ثم B وأكمل B ثم A وتحقق من بقاء B ظاهرا. كرر الاختبار بفشل A بعد نجاح B. وحرّر المالك قبل الاكتمال وتحقق من عدم اعتماد واجهة. تثبت هذه الاختبارات عقود العمر والحداثة دون تأخيرات حقيقية أو خادم حي. قد ينجح اختبار ينام عددا عشوائيا من المللي ثانية بالمصادفة دون أن يختبر الترتيب المسبب للمشكلة.
الأخطاء الشائعة وإصلاحها
يستبدل بحث قديم نتيجة أحدث
- لماذا يحدث؟
- اعتُبر ترتيب الاكتمال مماثلا لترتيب الطلب.
- كيف تصلحه؟
- افحص هوية الطلب قبل اعتماد النجاح والخطأ.
- كيف تتجنب تكراره؟
- تحكم بترتيب الاكتمال باستخدام بدائل مزيفة.
تكرر إعادة البناء التحميل
- لماذا يحدث؟
- يعاد إنشاء Future داخل build.
- كيف تصلحه؟
- خزّن العملية أو حدّثها عند حد مالك صريح.
- كيف تتجنب تكراره؟
- أعد بناء الأب أثناء طلب معلق.
يظهر الطلب الفاشل كغياب نتائج
- لماذا يحدث؟
- استبدلت معالجة الخطأ الفشل بمجموعة فارغة.
- كيف تصلحه؟
- مثّل الخطأ والفراغ الناجح بصورة منفصلة.
- كيف تتجنب تكراره؟
- اختبر واجهتي الفشل والنتائج الفارغة.
اختبر فهمك
1. هل يمنع mounted النتائج المتقادمة ما دامت الشاشة مفتوحة؟
اعرض الحل المشروح
لا. يثبت فقط أن State لم تُحرّر. قد ينتمي الاستعلامان A وB إلى المالك الموجود نفسه. أضف هوية مدخل أو جيل، ولا تعتمد إلا النتيجة المطابقة لسياسة العملية الحالية.
2. كيف ينبغي لفشل متقادم أن يؤثر في بحث أحدث ناجح؟
اعرض الحل المشروح
ينبغي ألا يستبدل النجاح الأحدث ضمن سياسة أحدث نتيجة. طبّق فحص التذكرة في فرع الخطأ كما في فرع النجاح. واحفظ الدليل التشخيصي منفصلا عند الحاجة دون عرض الفشل المتقادم بوصفه الحالة الحالية للشاشة.
أهم ما تعلمته
- يمثل Future اكتمالا مستقبليا واحدا
- اختبر ترتيب الاكتمال صراحة