عندما درست Javascript ، صادفت العديد من المقالات حول الدالات والعمليات غير المتزامنة مرارًا وتكرارًا. على الرغم من المزايا التي لا شك فيها لمثل هذه الوظيفة ، في كل مرة كنت أواجه صعوبة في القائمة التي استشهد بها المؤلفون. الكلمات تغيرت ، والجوهر بقي كما هو ، عصيدة كانت تختمر في رأسي. تحت خفض - دليل صغير للتنمية التاريخية وإصدارات ECMA.
لماذا نحتاج إلى عمليات غير متزامنة؟
يمكن لبرنامج الكمبيوتر أداء عدد غير محدود من المهام. ليس سراً أن تطبيقات الويب يجب أن تعمل مع العديد من المهام المختلفة ، والتي غالباً ما تحتاج إلى استخدام نفس البيانات. على وجه الخصوص ، أحد أكثر الأمثلة شيوعًا هو عرض معلومات المستخدم (UI) واسترداد المعلومات باستخدام طلبات الخادم. ليس من المستغرب أن يواجه كل مطور ويب تقريبًا ذلك: العمل مع قاعدة بيانات معينة ، وتوفير واجهة مستخدم ، وتنظيم بعض واجهات برمجة التطبيقات - كل هذا حرفيًا في كل مهمة اختبار لا يقتصر عليها مبرمجو JS.
لماذا لا تنفذ الأوامر بالتتابع؟في كثير من الأحيان لا يمكن الحصول على المعلومات التي يحتاجها المستخدم إلا بعد فترة زمنية طويلة. إذا قمت بتنظيم البرنامج على النحو التالي:
- الحصول على معلومات من الموقع https: / some / api / item / 1
- عرض معلومات حول العنصر الأول على الشاشة.
ستظهر صعوبات خطيرة عند عرض الصفحة وإنشاء انطباع جيد على المستخدم (ما يسمى بتجربة المستخدم). فقط تخيل: صفحة ، على سبيل المثال ، سيتعين على Netflix أو Aliexpress الحصول على بيانات من مئات قواعد البيانات قبل البدء في عرض المحتويات على المستخدم. سيكون هذا التأخير مشابهًا لتحميل مستوى لعبة ثلاثية الأبعاد ، وإذا كان اللاعب جاهزًا للانتظار ، فإن مستخدم موقع الويب يريد الحصول على أكبر قدر من المعلومات في الوقت الحالي.
تم العثور على الحل:
عمليات غير متزامنة . في حين أن الخيط الرئيسي للبرنامج منشغل في تهيئة وعرض عناصر موقع الويب على القماش ، فإنه يخرج المهام أيضًا إلى سلاسل الرسائل الأخرى بروح "
الحصول على البضائع للمستخدم ". بمجرد أن يكمل هذا الخيط عمله ، فإن المعلومات "تستقر" في الخيط الرئيسي ، وتصبح متاحة للعرض ، وفي صفحة الويب نفسها ، هناك عنصر نائب معين - كائن يشغل مساحة لمعلومات المستقبل.

في هذه المرحلة ، يتم عرض الصفحة بالفعل ، على الرغم من حقيقة أن بعض الطلبات لم تمر بعد.

على الأرجح ، في مكان ما في أسفل الصفحة ، تقوم بعض الطلبات الإضافية بإرجاع قيمة ، وتستمر الصفحة في التحديث وتقديمها بشكل حيوي ، دون أي إزعاج للمستخدم.
ES5 والإصدارات الأقدم: رد الاتصال
قبل المتابعة في مراجعة عمليات الاسترجاعات ، دعونا نلقي نظرة على / معرفة
وظائف النظام الأعلى .
وظيفة الترتيب الأعلى في JS هي
وظيفة تأخذ وظيفة أخرى كوسيطة . هنا مثال:
objectIsString(objectRef) { return typeof(objectRef) === 'String'; } listOfObjects.filter(objectIsString);
وبالتالي ، تم تمرير دالة objectIsString إلى الدالة ذات الترتيب الأعلى - عامل التصفية - والذي يسمح بتصفية listOfObjects وترك كائنات سلسلة النوع فقط في القائمة.
رد الفعل يعمل بطريقة مماثلة. هذه دالة يتم تمريرها كوسيطة لوظيفة أخرى. في أغلب الأحيان ، يتم استخدام وظيفة setTimeout كمثال لوظيفة تقوم بمعالجة عمليات الاسترجاعات. بشكل عام ، يتم استخدامه كـ setTimeout (دالة ، timeoutValue) ، حيث تكون الوظيفة عبارة عن وظيفة رد اتصال يتم تنفيذها بواسطة المستعرض بعد فترة زمنية محددة في المهلة.
setTimeout(console.log(1), 2000); console.log(2);
طباعة 2 1.
ES 6: الوعود
في المعيار 6 ، تم تقديم نوع جديد - الوعد (الوعد ، فيما بعد - الوعد). الوعد هو نوع له كائناته من ثلاث حالات: معلقة ، تم الوفاء بها ، مرفوضة. علاوة على ذلك ، مع آخر حالتين يمكنك "ربط" الوظائف - عمليات الاسترجاعات. بمجرد أن تصبح العملية غير المتزامنة الموصوفة في إطار الوعد نفسه ناجحة / فاشلة ، سيتم استدعاء الوظيفة المرتبطة بها. تسمى هذه العملية "عمليات الاسترجاعات المعلقة" ، ويتم تنفيذها باستخدام أساليب الوصل ثم الوعد نفسها. الفرق هو أنه عند استدعاء الوسيطات ، يتم نقل وظيفتين - في حالة النجاح (onFullfillment) والفشل (onRejected) ، في حين يقبل catch ، لأنه ليس من الصعب تخمينه ، إلا أنه دالة لمعالجة الأخطاء في وعد. من أجل تحديد ما إذا كان قد تم تنفيذ الوعد بنجاح في حالة معينة ، وكذلك تحديد النتيجة التي تم إرجاعها
دعونا إنشاء واستخدام وعد على مراحل.
الآن إضافة معالجات الأحداث باستخدام الأسلوب ثم. تكون الحجة إلى الدالة التي تتعامل مع النجاح هي النتيجة ، في حين أن الوسيطة إلى الدالة للتعامل مع فشل الوعد هي خطأ.
promise .then( result => { }, error => { } );
انتهى
لذلك ، سنصف مرة أخرى عملية إنشاء وعد بإيجاز:
- تهيئة الكائن (وعد جديد)
- نقوم بتمرير وظيفة العزم و / أو الرفض باعتبارها الوسيطة الوحيدة للمُنشئ. يجب أن تحتوي الوظيفة على عملية واحدة غير متزامنة على الأقل
- باستخدام أساليب then / catch ، نضيف وظائف - معالجات النتائج.
مولدات. العائد
أيضا في معيار ES6 ، تم تعريف نوع جديد من الوظائف - المولدات. هذه الوظائف لديها القدرة على إرجاع قيم مختلفة عدة مرات مع مكالمات متطابقة للوهلة الأولى. دعونا نرى كيف يفعلون ذلك ولماذا استخدامه.
النموذج القياسي للمولد: function * functionName () {}. في نص الدالات نفسها ، يتم استخدام كلمة العائد لإرجاع قيمة متوسطة.
كمثال ، خذ بعين الاعتبار المولد التالي:
function* generateNumber() { yield 1; yield 2; return 3; }
في الوقت الحالي ، يكون المولد في بداية تنفيذه. في كل مرة يتم استدعاء طريقة المولد التالي ، سيتم تنفيذ الكود الموصوف قبل أقرب عائد (أو عائد) ، وسيتم أيضًا إرجاع القيمة المشار إليها في السطر مع إحدى هذه الكلمات.
Let one = generateNumber.next();
المكالمة التالية ستُرجع القيمة 2. بالطريقة نفسها ، أما المكالمة الثالثة فتُرجع القيمة 3. وتُنهي تنفيذ الوظيفة.
Let two = generateNumber.next();
على الرغم من هذا ، لا يزال من الممكن الوصول إلى المولد من خلال الوظيفة
التالية . ومع ذلك ، فسوف تُرجع نفس القيمة: الكائن {done: true}.
ES7. متزامن / تنتظر
جنبا إلى جنب مع الرغبة في إرضاء عشاق OOP بمساعدة فصول السكر النحوية وتقليد الميراث ، يحاول مبتكرو ES7 تسهيل فهم جافا سكريبت ولأولئك الذين يحبون كتابة الشفرة المتزامنة. باستخدام عمليات التزامن / الانتظار ، يمكن للمستخدم كتابة تعليمات برمجية غير متزامنة تشبه قدر الإمكان التزامن. إذا كنت ترغب في ذلك ، يمكنك التخلص من الوعود التي تمت دراستها مؤخرًا وإعادة كتابة الشفرة بأقل التغييرات.
النظر في مثال:
باستخدام الوعود:
requestBook(id) { return bookAPIHelper.getBook(id).then(book => {console.log(book)}); }
باستخدام المتزامن / تنتظر.
async requestBook(id) { Const book = await bookAPIHelper.getBook(id); Console.log(book); }
لنصف ما رأيناه:
1) غير متزامن - الكلمة الأساسية المضافة عند الإعلان عن وظيفة غير متزامنة
2) انتظر - الكلمة الأساسية المضافة عند استدعاء وظيفة غير متزامن.
ES8. التكرار غير المتزامن
أصبح التكرار عبر البيانات متزامنًا في ES5. بعد اثنين من المواصفات ، تقرر إضافة إمكانية التكرار غير المتزامن في مصادر البيانات غير المتزامنة. الآن ، عندما يتم استدعاء التالي () ، لن يُرجع ذلك {value، done} ، لكن الوعد (انظر ES6).
لنلقِ نظرة على الدالة createAsyncIterable (القابلة للتكرار).
async function* createAsyncIterable(iterable) { for (const elem of iterable) { yield elem; } }
كما ترى ، تقوم الدالة بتهيئة المجموعة ، لكل مكالمة يتم إرجاع عناصر منها بالقيمة المحددة في التكرار.
const asyncIterable = createAsyncIterable(['async 1', 'async 2']); const asyncIterator = asyncIterable[Symbol.asyncIterator](); asyncIterator.next() .then(result => { console.log(result);
علاوة على ذلك ، يحدد المعيار الجديد حلقة انتظار انتظار ملائمة لهذه العمليات.
for await (const x of createAsyncIterable(['a', 'b']))
TL ؛ د
ليس من الضروري على الإطلاق معرفة وتذكر أي إصدار من ECMAScript هذا أو بناء الجملة ينتمي إليه ، خاصةً إذا كنت بدأت للتو تعرفك على سلوك غير متزامن في JS. في الوقت نفسه ، ستتيح دراسة عدم التزامن بالترتيب الذي اقترحه تاريخ تطوير المواصفات للمبرمج تمامًا فهم بناء الجملة والإرشادات التي تم تمريرها إلى مشغل JS ، ولكن أيضًا اتباع منطق تحسين ECMAScript كمنتج ، لفهم الاتجاهات التي تمليها مطوري JS ، وفصلها وقبولها .
باختصار ، ثم:
الاسترجاعات <= ES5
الوعود ، العائد (المولدات): ES6
المتزامن / تنتظر: ES7
مآثر المتزامن: ES8