نحن نتقن / ننتظر مثال حقيقي

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

الصورة

قبل ظهور التزامن / الانتظار ، تم استخدام عمليات الاسترجاعات والوعود في تطوير آليات برنامج غير متزامن. يقترح مؤلف المادة ، التي ننشر ترجمتها اليوم ، أولاً التذكير بكيفية كتابة التعليمات البرمجية بالطريقة القديمة ، ثم ، باستخدام مثال حقيقي ، دراسة استخدام المتزامن / انتظار.

الاسترجاعات


فيما يلي نموذج تعليمة برمجية تستخدم عمليات الاسترجاعات (وظائف رد الاتصال):

setTimeout(() => {  console.log('This runs after 1000 milliseconds.'); }, 1000); 

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

 asyncCallOne(() => { asyncCallTwo(() => {   asyncCallThree(() => {     asyncCallFour(() => {       asyncCallFive(() => {         //         })     })   }) }) }) 

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

الوعود


فيما يلي رمز مثال يستخدم الوعود (كائنات الوعد):

 const promiseFunction = new Promise((resolve, reject) => { const add = (a, b) => a + b; resolve(add(2, 2)); }); promiseFunction.then((response) => { console.log(response); }).catch((error) => { console.log(error); }); 

promiseFunction() الدالة promiseFunction() من هذا المثال كائن Promise ، وهو إجراء معين تقوم به الوظيفة. يشير استدعاء أسلوب resolve() إلى الوعد باستكمال التشغيل بنجاح. في مثل هذه الإنشاءات ، يتم استخدام طريقة الوعود .then() أيضًا - مع مساعدتها ، بعد حل الوعد بنجاح ، يمكنك تنفيذ رد اتصال معين. يتم .catch() الأسلوب .catch() إذا حدث خطأ ما أثناء عمل الوعد.

وظائف غير متزامنة


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

يتم إنشاء وظائف غير متزامنة باستخدام الكلمة الأساسية غير async عند الإعلان عن دالة. يبدو مثل هذا:

 const asyncFunction = async () => { //  } 

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

قارن بين تشغيل وظيفة غير متزامنة ووعد بإرجاع سلسلة:

 //   const asyncGreeting = async () => 'Greetings'; //  const promiseGreeting = () => new Promise(((resolve) => { resolve('Greetings'); })); asyncGreeting().then(result => console.log(result)); promiseGreeting().then(result => console.log(result)); 

من السهل أن ترى أن استخدام async يتيح لك كتابة التعليمات البرمجية غير المتزامنة التي تبدو متزامنة. هذا الرمز هو أسهل بكثير للعمل مع.

الآن وقد غطينا الأشياء الأساسية ، دعنا ننتقل إلى مثالنا.

محول العملات


▍ التحضير الأولي


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

على وجه الخصوص ، سنستخدم هنا بيانات من مصدرين غير متزامنين للمعلومات:

  1. خدمة Currencylayer.com . في هذا الموقع ، ستحتاج إلى إنشاء حساب مجاني والحصول على مفتاح للوصول إلى API (API Access Key). من هنا سنأخذ البيانات اللازمة لتحويل المبلغ من عملة إلى أخرى.
  2. خدمة restcountries.eu . يمكن استخدامه دون تسجيل. من هنا ، نحمل بيانات حول المكان الذي يمكنك فيه استخدام العملة التي حولنا بها المبلغ المحدد من المال.

قم بإنشاء دليل جديد وقم بتشغيل الأمر npm init فيه. عندما يسألنا البرنامج عن اسم الحزمة التي يتم إنشاؤها ، سنقدم لك currency-converter . لا يمكنك الإجابة عن أسئلة البرنامج الأخرى بالضغط على Enter رداً. بعد ذلك ، قم بتثبيت حزمة npm install axios --save في مشروعنا عن طريق تشغيل الأمر npm install axios --save في npm install axios --save . قم بإنشاء ملف جديد يسمى currency-converter.js .

لنبدأ في كتابة رمز البرنامج عن طريق توصيل Axios في هذا الملف:

 const axios = require('axios'); 

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

first الوظيفة الأولى هي التحميل غير المتزامن لبيانات العملة


لنقم بإنشاء getExchangeRate() غير متزامنة getExchangeRate() : من fromCurrency إلى toCurrency :

 const getExchangeRate = async (fromCurrency, toCurrency) => {} 

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

 const response = await axios.get('http://www.apilayer.net/api/live?access_key=[    API]'); 

بعد تلقي استجابة النظام ، يمكن العثور على البيانات التي نحتاجها في كائن response.data.quotes على response.data.quotes . فيما يلي جزء الكائن الذي يحتوي على بيانات تهمنا (تظهر في البرنامج response.data ):

 {  "success":true,  "terms":"https:\/\/currencylayer.com\/terms",  "privacy":"https:\/\/currencylayer.com\/privacy",  "timestamp":1547891348,  "source":"USD",  "quotes":{     "USDAED":3.673042,     "USDAFN":75.350404,     "USDALL":109.203989, ...     "USDZWL":322.355011  } } 

ضع الكائن مع أسعار الصرف في rate ثابت:

 const rate = response.data.quotes; 

يمكن العثور على رمز العملة الأساسية على response.data.source . نكتب رمز العملة الأساسية في قاعدة baseCurrency :

 const baseCurrency = response.data.source; 

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

 const usd = 1 / rate[`${baseCurrency}${fromCurrency}`]; 

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

الآن ، من أجل الحصول على سعر الصرف من fromCurrency إلى toCurrence ، نقوم بضرب usd الثابت في سعر toCurrency . يبدو مثل هذا:

 const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`]; 

نتيجة لذلك ، سنعود ما يحصل في exchangeRate . إليك ما يبدو عليه الكود الكامل:

 const getExchangeRate = async (fromCurrency, toCurrency) => {   try {     const response = await axios.get('http://www.apilayer.net/api/live?access_key=[    API]');     const rate = response.data.quotes;     const baseCurrency = response.data.source;     const usd = 1 / rate[`${baseCurrency}${fromCurrency}`];     const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`];     return exchangeRate;   } catch (error) {     throw new Error(`Unable to get currency ${fromCurrency} and ${toCurrency}`);   } }; 

يرجى ملاحظة أن استخدام try / catch العادي يستخدم لمعالجة الأخطاء التي قد تحدث أثناء تنفيذ الاستعلام.

second الوظيفة الثانية هي التحميل غير المتزامن لبيانات الدولة


getCountries() الثانية ، getCountries() ، التي تقوم بشكل غير متزامن بتحميل المعلومات حول البلدان التي يمكنك فيها استخدام العملة التي سنقوم بتحويل المبلغ المحدد بعملة أخرى ، سوف تأخذ وسيطة currencyCode :

 const getCountries = async (currencyCode) => {} 

لتحميل البيانات ، نستخدم الأمر التالي:

 const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`); 

على سبيل المثال ، إذا استخدمنا رمز HRK (kuna الكرواتي) في الطلب ، فسنستلم رمز JSON ردًا على ذلك ، ويرد جزء منه أدناه:

 [   {     "name":"Croatia", ...  } ] 

إنها مجموعة من الكائنات التي تحتوي على معلومات حول البلدان. تحتوي خصائص name هذه الكائنات على اسم البلد. يمكنك الوصول إلى هذا الصفيف باستخدام بنية response.data . نطبق طريقة الصفيف map() لاستخراج أسماء البلدان من البيانات المستلمة وإرجاع هذه البيانات من getCountries() ، والتي ستكون عبارة عن مجموعة من أسماء الدول:

 return response.data.map(country => country.name); 

فيما يلي رمز الوظيفة getCountries() الكامل:

 const getCountries = async (currencyCode) => {   try {     const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);     return response.data.map(country => country.name);   } catch (error) {     throw new Error(`Unable to get countries that use ${currencyCode}`);   } }; 

▍ الوظيفة الثالثة - جمع البيانات والإخراج


convertCurrency () الثالثة غير المتزامنة ، convertCurrency () ، ستقبل الوسيطات من fromCurrency و toCurrency amount - رموز العملة والمبلغ.

 const convertCurrency = async (fromCurrency, toCurrency, amount) => {} 

فيه ، نحصل أولاً على سعر الصرف:

 const exchangeRate = await getExchangeRate(fromCurrency, toCurrency); 

ثم نقوم بتحميل قائمة الدول:

 const countries = await getCountries(toCurrency); 

بعد ذلك ، نقوم بإجراء التحويل:

 const convertedAmount = (amount * exchangeRate).toFixed(2); 

وبعد جمع جميع البيانات اللازمة ، نرجع السطر الذي سيراه المستخدم في البرنامج:

 return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`; 

هنا هو رمز الوظيفة الكاملة:

 const convertCurrency = async (fromCurrency, toCurrency, amount) => {   const exchangeRate = await getExchangeRate(fromCurrency, toCurrency);   const countries = await getCountries(toCurrency);   const convertedAmount = (amount * exchangeRate).toFixed(2);   return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`; }; 

يرجى ملاحظة أن هذه الوظيفة لا تحتوي على كتلة try / catch ، لأنها تعمل فقط مع النتائج المقدمة إليها من الوظيفتين الموصوفتين سابقًا.

art ابدأ تشغيل البرنامج


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

 convertCurrency('EUR', 'HRK', 20)   .then((message) => {     console.log(message);   }).catch((error) => {     console.log(error.message);   }); 

هنا نريد أن نعرف مقدار التبادل الكرونا مقابل 20 يورو وعلى طول الطريق لمعرفة أي الدول يمكن أن تنفق هذه الأموال.

ندعو البرنامج عن طريق إدخال الأمر التالي في المحطة:

 node currency-converter.js 

ردا على ذلك ، نحصل على ما يلي.


نتيجة البرنامج

هنا ، فقط في حالة ، الكود الكامل لمشروعنا.

 const axios = require('axios'); const getExchangeRate = async (fromCurrency, toCurrency) => {   try {     const response = await axios.get('http://www.apilayer.net/api/live?access_key=[    API]');     const rate = response.data.quotes;     const baseCurrency = response.data.source;     const usd = 1 / rate[`${baseCurrency}${fromCurrency}`];     const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`];     return exchangeRate;   } catch (error) {     throw new Error(`Unable to get currency ${fromCurrency} and ${toCurrency}`);   } }; const getCountries = async (currencyCode) => {   try {     const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);     return response.data.map(country => country.name);   } catch (error) {     throw new Error(`Unable to get countries that use ${currencyCode}`);   } }; const convertCurrency = async (fromCurrency, toCurrency, amount) => {   const exchangeRate = await getExchangeRate(fromCurrency, toCurrency);   const countries = await getCountries(toCurrency);   const convertedAmount = (amount * exchangeRate).toFixed(2);   return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`; }; convertCurrency('EUR', 'HRK', 20)   .then((message) => {     console.log(message);   }).catch((error) => {     console.log(error.message);   }); 

ملخص


نأمل أن يساعد هذا المثال الخاص باستخدام بنية async / انتظار في ظروف حقيقية أولئك الذين لم يفهموا هذه البنية من قبل على اكتشافها.

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

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


All Articles