كيفية العمل مع المزامنة / الانتظار في حلقات JavaScript

كيفية تشغيل حلقات غير متزامنة بالترتيب أو بالتوازي في JavaScript؟


قبل القيام بالسحر غير المتزامن ، أود أن أذكركم بحلقات الحلقات الكلاسيكية المتزامنة.


حلقات متزامنة


منذ وقت طويل كتبت الحلقات بهذه الطريقة (ربما أنت أيضًا):


for (var i=0; i < array.length; i++) { var item = array[i]; //  -  item } 

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


 array.forEach((item) => { //  -  item }); 

جافا سكريبت تتطور بسرعة كبيرة. تظهر ميزات جديدة وبناء جملة. أحد التحسينات المفضلة لدي هي المزامنة / الانتظار .


الآن يمكنني استخدام بناء الجملة هذا في كثير من الأحيان. وفي بعض الأحيان تكون هناك مواقف عندما أحتاج إلى القيام بشيء مع عناصر الصفيف بشكل غير متزامن.


حلقات غير متزامنة


كيفية استخدام await في جسم الحلقة؟ دعنا فقط نحاول كتابة وظيفة غير متزامنة ونتوقع مهمة معالجة كل عنصر:


 async function processArray(array) { array.forEach(item => { //       //     ! await func(item); }) } 

هذا الكود سوف يلقي خطأ. لماذا؟ لأننا لا نستطيع استخدام await داخل وظيفة متزامن. كما ترون ، processArray هي وظيفة غير متزامنة. لكن الوظيفة المجهولة التي نستخدمها في forEach متزامنة .


ما الذي يمكن عمله حيال ذلك؟


1. لا تنتظر نتيجة التنفيذ


يمكننا تعريف وظيفة مجهولة بأنها غير متزامنة:


 async function processArray(array) { array.forEach(async (item) => { await func(item); }) console.log('Done!'); } 

ولكن forEach لن تنتظر المهمة لإكمالها. forEach هي عملية متزامنة. وقالت إنها ببساطة سوف تبدأ المهام والمضي قدما. دعونا نتحقق من اختبار بسيط:


 function delay() { return new Promise(resolve => setTimeout(resolve, 300)); } async function delayedLog(item) { //    await  Promise //    delay await delay(); console.log(item); } async function processArray(array) { array.forEach(async (item) => { await delayedLog(item); }) console.log('Done!'); } processArray([1, 2, 3]); 

في وحدة التحكم ، سنرى:


 Done! 1 2 3 

في بعض الحالات ، قد تكون هذه نتيجة طبيعية. ولكن لا يزال ، في معظم الحالات ، هذا ليس منطقًا مناسبًا.


2. معالجة الدورة بالتتابع


من أجل انتظار نتيجة تنفيذ جسم الحلقة ، نحتاج إلى العودة إلى الحلقة القديمة "الجيدة". ولكن هذه المرة سوف نستخدم نسختها الجديدة مع for..of (بفضل بروتوكول التكرار ):


 async function processArray(array) { for (const item of array) { await delayedLog(item); } console.log('Done!'); } 

هذا سوف يعطينا النتيجة المتوقعة:


 1 2 3 Done! 

سيتم معالجة كل عنصر من الصفيف بالتتابع. لكن يمكننا تشغيل الحلقة بالتوازي!


3. معالجة الحلقة في نفس الوقت


تحتاج إلى تعديل الرمز قليلاً لبدء العمليات بشكل متوازٍ:


 async function processArray(array) { //  "map"    const promises = array.map(delayedLog); //       await Promise.all(promises); console.log('Done!'); } 

يمكن تشغيل هذا الرمز عدة مهام delayLog متواز. ولكن كن حذرا مع صفائف كبيرة. يمكن أن تكون المهام كثيرة جدًا صعبة للغاية بالنسبة لوحدة المعالجة المركزية والذاكرة.


أيضا ، يرجى عدم الخلط بين "المهام الموازية" من المثال مع التوازي الحقيقي والخيوط. هذا الرمز لا يضمن التنفيذ الموازي. كل شيء يعتمد على نص الحلقة (في المثال ، يتم delayedLog ). يمكن إجراء طلبات الشبكة وأخصائيي الويب وبعض المهام الأخرى بشكل متوازٍ.

Source: https://habr.com/ru/post/ar435084/


All Articles