كيفية رمز جافا سكريبت المزامنة بشكل أفضل

تجنب الوعد هرم الموت (وعد الجحيم)

مرحبا!

كما هو محدد في مستندات Mozilla:

"يمثل كائن Promise الإكمال (أو الفشل) النهائي لعملية غير متزامنة وقيمتها الناتجة."

سهل هكذا. يحتوي كائن الوعد على طريقتين قابلتين للتسلسل: ثم التقاط.

لذلك ، لتلخيص:

  1. ثم يتم تنفيذ (مرة واحدة فقط) إذا تم حل وعدها.
  2. يتم التعامل مع أي قيمة (ما لم يكن هناك رفض للوعد ، بالطبع) يتم إرجاعها من الداخل كقيمة دقة الوعد ، وبالتالي يمكن التعامل معها في السلسلة التالية أو في المستوى الأعلى.
  3. بعد ذلك يتم تنفيذ ، الخ ...
  4. يتم تنفيذ "الصيد" (مرة واحدة فقط) في حالة رفض أي وعد في السلسلة.

المشكلة

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

كيف حلها؟

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

أي اقتراحات؟ نعم فعلا!

1. تجنب استخدام عمليات الاسترجاعات بكل الوسائل. حتى يومنا هذا ، لا ينبغي لأحد استخدام عمليات الاسترجاعات للتعامل مع عمليات المزامنة ، ومع ذلك ، لسبب ما ، لا يزال هناك العديد من المكتبات تقوم بذلك. لذلك ، تجنب ذلك في التعليمات البرمجية الخاصة بك ، ولف الوظائف التي تستند إلى رد الاتصال من طرف ثالث في الوعود.

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

3. عند تنفيذ وظائف غير متزامنة في سلسلة متتالية (نتيجة واحدة هي مدخلات التالي) أو في سلسلة (واحدة تلو الأخرى) ، بدلاً من تداخلها ، جرب تسلسل بسيط.

4. الوظائف هي مواطنين من الدرجة الأولى في JavaScript مما يعني أنه يمكنك تمريرها كمعلمات إلى وظائف أخرى. ونظرًا لأنه يمكنك تعيين دالة مجهولة لمتغير ، فمن الأفضل لك تمرير المتغير كعنصر أساسي إلى وظائفك في كل مرة.

5. تذكر وظائف السهم ميزة العودة الضمنية.

لاحظ أن استخدام وظائف الأسهم يجعل من الصعب تصحيح التعليمات البرمجية الخاصة بك ، لأن وظائف الأسهم مجهولة ، مما يعني أنك لن ترى الوظيفة في تتبع الخطأ. اقرأ المزيد هنا.

6. كل شيء يتم إرجاعه منذ ذلك الوقت (باستثناء رفض وعد صريح) ، يُعد قيمة دقة الوعد ، بحيث يمكنك فقط معالجة دقة الوعد في اليوم التالي:

لذا نظرًا لأن getProductsRelatedToOrders يتلقى الطلبات كمعلمة يتم حلها بواسطة getOrders ، فبدلاً من استدعاء ثم مرة أخرى داخل أول واحد ، يمكنك فقط تسلسلها.

هذا الجزء:

`products.map (product => ({... product، someImportantValue}))`

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

لاحظ أننا لم نستخدم Promise.resolve أو Promise.all. في مستوى أعلى ، سيتم استلام هذه المجموعة الجديدة كقيمة دقة الوعد.

7. لا تنسى أبدا للقبض.

7.1 يفضل اصطياد الأخطاء على المستوى الأعلى.

7.2 تجنب أكثر من مكالمة صيد واحدة في نفس الوظيفة.

7.3 إذا كنت ملفوفًا لواجهة برمجة التطبيقات ، فهناك فرصة كبيرة لأنك سترغب في تغيير تنسيق أخطاءها أو إضافة معلومات إضافية ؛ قم بذلك في وظيفة الالتفاف الخاصة بك وإرجاع رفض الوعد.

8. استخدام المتزامن / انتظار بناء الجملة. على الرغم من أن العديد من المطورين يجادلون بأنه لا ينبغي لنا ذلك ، نظرًا لأنه السكر النحوي في أعلى الوعود ، إلا أنه يساعدنا في الواقع على تجنب جميع المشاكل المتعلقة بتنفيذ وظائف المتتالية والتسلسلية. لذا نعم ، يجب أن تجربها.

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

9. إذا اخترت استخدام بناء جملة async / انتظار:

9.1 استخدم try / catch.

9.2 لا تخلط بين الوعد وتزامن / انتظار بناء الجملة في نفس الوظيفة. على الرغم من أنه يمكنك استدعاء وعد ، فالرجاء منهج أو إرجاع Promise.resolve أو Promise.reject من دالة تم وضع علامة عليها غير متزامنة ، تجنب ذلك ، لمجرد التناسق. تذكر أن كل شيء يتم إرجاعه من وظيفة غير متزامن سيعتبر قيمة دقة الوعد. سيتم اعتبار أي خطأ يتم طرحه سببًا لرفض الوعد.

9.3 كما في الوعود ، تعامل مع الأخطاء في المستوى الأعلى

9.4 على الرغم من أنه يمكنك دائمًا استخدامه ، إلا أنه مناسب بشكل خاص لتلك الحالات عندما يكون هناك الكثير من تداخل الوعد ، عندما تعتمد الوعود على أكثر من قيمة دقة الوعد السابقة.

10. عند التعامل مع عمليات متعددة غير متزامنة "بالتوازي" ، يمكنك الاستفادة من الخريطة و Promise.all.

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

11. سجلات. تقسيم التعليمات البرمجية الخاصة بك إلى وظائف متعددة غير متزامنة ، بعضها مع وعود متداخلة ، (ربما) أخرى ذات بناء جملة متزامن / انتظار ، يمكن أن يصبح تصحيحه سريعًا ، لا سيما بالنظر إلى الاستخدام المكثف لوظائف السهم هذه الأيام. لذا استخدم مكتبة تسجيل وصنع سجلات وصفية في كل وظيفة حتى تتمكن من تتبع تدفق البيانات بالفعل.

12. تذكر المثال في النقطة 4.

الآن اعتبر أنه يمكن أيضًا إرجاع الوظائف كنتيجة لوظيفة أخرى. تخيل المثال السابق ، لكن هذه المرة تحتاج دالة getOrders إلى كائن موجود في نفس المستوى حيث تم استدعاء findUsers. قد تعتقد ، "حسنًا ، يمكنني تمريرها إلى findUsers ثم أعدها". الشيء هو أنه من خلال القيام بذلك ، يمكن أن يكون الأمر مضللاً حول ما تقوم به أداة findUser ، بالإضافة إلى ما إذا كان الشيء الوحيد الذي تفعله دالة مع param هو إرجاعها ، ثم يجب عدم إعلان تلك المعلمة في المقام الأول.

إذا كنت تريد معرفة المزيد ، تحقق من هذه المقالة حول الكاري والتطبيق الجزئي.

العثور على الجبن!