المقدمة

كثيرًا ما نسمع أن لغة Dart، وهي اللغة الأساسية لإطار Flutter، تعتمد على مبدأ الـ Single Thread، ولكن ما المقصود بهذا المفهوم؟ وما هو الـ Thread أصلًا؟ وكيف تعمل المفاهيم المرتبطة به مثل Isolate وEvent Loop في بيئة Flutter؟

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


مبدأ الـ Single Thread

بدايةً، يمكننا تعريف الـ Thread بأنه وحدة التنفيذ داخل البرنامج، أي المسار الذي تُنفّذ فيه مجموعة من الأوامر والتعليمات البرمجية.

وعندما نقول إن Dart تعتمد على Single Threaded Execution، فإننا نعني أنها تستخدم مسار تنفيذ واحد فقط لمعالجة جميع المهام. هذا المسار يُنفّذ التعليمات بشكل تسلسلي ومتزامن (Synchronous)، أي أن كل مهمة تنتظر انتهاء المهمة التي قبلها لتبدأ، دون وجود تنفيذ متوازي بشكل افتراضي.

ولكن، ماذا يحدث إذا كانت إحدى هذه المهام تستغرق وقتًا طويلًا، مثل طلب بيانات من الإنترنت أو قراءة ملف كبير؟ في هذه الحالة، سيتوقف تنفيذ باقي المهام إلى أن تنتهي هذه المهمة، مما يؤدي إلى تجميد واجهة المستخدم وتجربة غير مرضية.

وهنا يظهر التساؤل: كيف يتعامل Flutter مع هذا التحدي؟ وكيف يمكنه تشغيل مهام متعددة أو ثقيلة دون التأثير على السلاسة العامة للتطبيق؟

الجواب يكمن في مفاهيم مثل Isolates و Event Loop، والتي سنشرحها في الأقسام القادمة من هذا المقال.


مفهوم الـ Isolate

لكي نتمكن من تنفيذ عدة مهام في نفس الوقت دون التأثير على سلاسة واجهة المستخدم (UI) أو التسبب في تجميد التطبيق، فإن Flutter يوفر لنا ميكانيكية تُدعى Isolate.

الـ Isolate هو ببساطة وحدة تنفيذ مستقلة، أو ما يمكن تشبيهه بـ "آلة صغيرة" مسؤولة عن تنفيذ المهام بشكل متوازي (Parallel Execution). كل Isolate يمتلك Thread خاص به، مما يعني أنه لا يشارك الذاكرة (Memory) مع الـ Isolates الأخرى، بل يعمل بشكل منفصل تمامًا.

في بيئة Flutter، يوجد ما يُعرف بـ Main Isolate، وهو المسؤول عن تنفيذ واجهة المستخدم والتعامل مع التفاعلات (الضغط على الأزرار، التحريك، إلخ). هذا الـ Isolate الرئيسي لا يشارك ذاكرته مع الـ Isolates الأخرى، ولذلك لا يمكنه التواصل معها بشكل مباشر.

لكن، كيف يتم التواصل إذًا؟ يتم ذلك عبر ما يُعرف بـ Message Passing باستخدام SendPort وReceivePort. بهذه الطريقة، يمكن للـ Isolates تبادل البيانات والرسائل فيما بينها دون الحاجة لمشاركة نفس الذاكرة، وهو ما يحافظ على الأمان ويمنع التعارضات في البيانات.

هذه الآلية تمنح Flutter القدرة على تشغيل مهام ثقيلة مثل تحليل البيانات أو قراءة ملفات ضخمة أو عمليات الـ JSON parsing في خلفية التطبيق، دون التأثير على الأداء العام أو استجابة الواجهة.


الـ Main Isolate والـ Event Loop  

عند تشغيل التطبيق وبدء تنفيذ دالة main()، يتم تلقائيًا إنشاء الـ Main Isolate، وهو الذي يتولى عرض واجهة المستخدم والتعامل مع تفاعلات المستخدم. في هذه اللحظة، هنا يظهر مفهوم أساسي يُعرف بـ حلقة الأحداث (Event Loop) المسؤولة عن متابعة و تتفيذ المهام التي يتلقاها ال Isolate، و  تبدأ  بالعمل لتضمن أن جميع المهام يتم تنفيذها بطريقة منظمة دون التأثير على الأداء.

مفهوم الـ Event Loop

يمكننا تعريف Event Loop على أنها الآلية المسؤولة عن مراقبة ومعالجة جميع أنواع الأحداث Events، مثل:  

✅ تفاعلات المستخدم مثل (tap)، (scroll)، (rebuild).  

✅ عمليات الإدخال/الإخراج (I/O): مثل قراءة الملفات أو تنفيذ طلبات **HTTP**.  

✅ الرسائل من Isolates أخرى  

تقوم Event Loop بتخزين هذه الأحداث في قوائم انتظار (Microtask Queue و Event Queue) وإدارتها حسب الأولوية والترتيب الزمني.  


الفرق بين الـ Microtask Queue و الـ Event Queue

✅ Microtask Queue  

  • تُستخدم للمهام عالية الأولوية التي يجب تنفيذها فورًا بعد انتهاء الكود الحالي، وقبل معالجة أي أحدث من Event Queue.  
  • مثالية للعمليات السريعة التي يجب إنجازها كمعالجة catch و then في Futures  

✅ Event Queue

  • تحتوي على المهام المؤجلة التي تنتظر دورها في التنفيذ، مثل:  
  • عمليات I/O (مثل قراءة الملفات أو طلبات الشبكة).  
  • (**Timer**, **Future.delayed**).  
  • أحداث واجهة المستخدم (مثل النقر والتمرير).  
  • يتم تنفيذها فقط بعد اكتمال جميع المهام في Microtask Queue  

كيف يتم ترتيب تنفيذ المهام في الـ Event Loop؟

  1. يبدأ تنفيذ الكود الرئيسي.
  2. عند الانتهاء، يتم تفريغ وتنفيذ جميع المهام في Microtask Queue.
  3. بعدها، تنتقل حلقة الأحداث إلى Event Queue وتبدأ بتنفيذ كل حدث بالتسلسل.
  4. بعد كل حدث، يتم التحقق من وجود مهام جديدة في Microtask Queue — وإذا وُجدت، يتم تنفيذها مباشرة قبل متابعة باقي الأحداث.
Main Isolate & Event Loop in Flutter
Main Isolate & Event Loop in Flutter

في الختام

من خلال هذا المقال، أصبح من الواضح أن Flutter لا يعتمد فقط على مسار تنفيذ واحد (Single Thread)، بل يستخدم نظامًا ذكيًا ومُعقّدًا خلف الكواليس يجمع بين Isolates و Event Loop لتنفيذ المهام بكفاءة دون التأثير على أداء واجهة المستخدم.

  • Isolate يوفّر إمكانية تنفيذ المهام بشكل متوازي دون مشاركة الذاكرة، مما يمنع التعارضات ويعزز الأمان.
  • Event Loop يُعدّ المحرك الأساسي الذي يدير الأحداث بشكل منظّم، من خلال Microtask Queue للمهام العاجلة، وEvent Queue للمهام المؤجلة.

 هذا النظام يمنح Flutter القدرة على:

  • الحفاظ على سلاسة واجهة المستخدم.
  • التعامل مع المهام الثقيلة بكفاءة.
  • ضمان توقيت دقيق لتنفيذ كل نوع من المهام

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