چگونه با این مثال، در Async / Await استاد شویم؟

13 خرداد 1398, خواندن در 7 دقیقه

جدول محتوا:

  1. مقدمه (callbackها، promiseها، async / await)
  2. یک مثال واقعی - یک تبدیل کننده ارز که داده‌های ناهمگام را از دو API دریافت می‌کند.

قبل از شروع، جای اشاره دارد که این مقاله حول محور زبان JavaScript می‌باشد و آموزش مربوطه را می‌توانید در این لینک بر روی راکت بیابید.

مقدمه

Async / await یک راه جدید برای نوشتن کد ناهمگام است. Async / await بر پایه promiseها ساخته شده است و از این رو همچنین غیر مسدود کننده هم هست.

تفاوت بزرگ آن در اینجاست که کد ناهمگام موجود در آن، کمی به مانند کد همگام به نظر رسیده و رفتار می‌کند. تمام قدرت آن در اینجاست.

گزینه‌های قبلی برای نوشتن کد ناهمگام، callbackها و promiseها بودند.

Callbackها در عمل

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

مشکل callbackها - Callback Hell بدنام

تو در تو کردن callbackها داخل callbackها، خیلی زود چنین ظاهری خواهد داشت:

Callback Hell

موقعیتی که در آن callbackها داخل callbackهای دیگر، به صورت تو در تو و تا چند مرحله نوشته شده‌اند، و درک و نگهداری کد را سخت‌تر می‌کنند.

Promiseها در عمل

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 یک promise را بر می‌گرداند که نمایانگر پردازش آن تابع است. تابع resolve به نمونه promise که به پایان رسیده است،‌ علامت می‌دهد.

سپس، ما .then و .catch را بر روی آن تابع promise فراخوانی می‌کنیم:
then - وقتی که promise مورد نظر تمام شود، یک callback که شما به آن منتقل کردید را اجرا می‌کند.
catch - وقتی که مشکلی پیش بیاید، یک callback که شما به آن منتقل کردید را اجرا می‌کند.

توابع Async

توابع async یک سینتکس تمیز و مرتب برای ما فراهم می‌کنند که ما را قادر می‌سازد تا کد کمتری را برای رسیدن به هدف مشابهی که با استفاده از promiseها به آن می‌رسیم، بنویسیم. Async چیزی بیش از یکی شکر سینتکسی برای promiseها نیست.

توابع async با پیوستن کلمه async قبل از تعریف تابع، و به این صورت ساخته می‌شوند:

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

توابع ناهمگام می‌توانند pause یا await شوند. کلمات کلیدی‌ای که فقط می‌توانند داخل یک تابع async استفاده شوند. Await هر چیزی که تابع async وقتی که انجام شده است بر می‌گرداند را بر می‌گرداند.

این تفاوت بین promiseها و async / await است:

// Async/Await
const asyncGreeting = async () => 'Greetings';

// Promises
const promiseGreeting = () => new Promise(((resolve) => {
  resolve('Greetings');
}));

asyncGreeting().then(result => console.log(result));
promiseGreeting().then(result => console.log(result));

Async / await ظاهری مشابه به کد همگام را دارد، و درک کردن کد همگام بسیار آسان‌تر است.

حال که ما پایه‌های این موضوع را پوشش داده‌ایم، بیایید به سراغ مثال واقعی خود برویم.

تبدیل کننده ارز

شفاف‌سازی و راه‌اندازی پروژه

در این آموزش، ما یک برنامه ساده ولی آموزشی خواهیم ساخت که قرار است دانش کلی موجود درباره async / await را بهبود بخشد.

برنامه، کد ارزی که می‌خواهیم از آن تبدیل کنیم، و کد ارزی که می‌خواهیم به آن تبدیل کنیم را به همراه مقدار پول می‌گیرد. سپس، نرخ تبادل فعلی را بر پایه داده‌های دریافت شده از APIها خروجی خواهد داد.

در این برنامه، ما می‌خواهیم داده‌ها را از دو منبع ناهمگام دریافت کنیم:

  1. Currency Layer - https://cuurencylayer.com - شما باید به صورت رایگان در آن ثبت نام کنید تا بتوانید از کلید دسترسی آن استفاده کنید. این API داده‌های مورد نیاز برای محاسبه نرخ بین ارزها را برای ما فراهم خواهد کرد.
  2. Rest Countries - http://restcountries.eu - این API اطلاعاتی را درباره این که یک ارز را در کجا می‌توانیم استفاده کنیم، به ما می‌دهد.

برای تازه‌کاران، باید بگویم که یک شاخه جدید بسازید و دستور npm init را اجرا کنید. تمام قدم‌ها را بگذرانید و axios را با تایپ کردن دستور npm i --save axios نصب کنید. یک فایل جدید به نام currency-converter.js بسازید.

در ابتدا با تایپ کردن این دستور، axios را ضروری کنید: const axios = require(‘axios’);.

بیایید به async / await وارد شویم

هدف ما این است که این برنامه سه تابع داشته باشد. نه یک، نه دو، بلکه سه تابع ناهمگام. اولین تابع قرار است داده‌های درباره ارز را دریافت کند. دومین تابع قرار است داده‌های درباره کشورها را دریافت کند. و سومین تابع هم قرار است آن اطلاعات را درباره یک مکان جمع‌آوری کرده و به زیبایی به کاربر نشان دهد.

اولین تابع - دریافت داده‌های ارز به صورت ناهمگام

ما یک تابع ناهمگام خواهیم ساخت که قرار است دو آرگومان با نام‌های fromCurrency و toCurrency را بگیرد.

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

حال ما باید داده‌ها را دریافت کنیم. با async / await، ما می‌توانیم داده‌ها را به طور مستقیم به یک متغیر اختصاص دهیم. فراموش نکنید که ثبت نام کرده، و کلید دسترسی صحیح مختص خود را وارد کنید.

const getExchangeRate = async (fromCurrency, toCurrency) => {
  const response = await axios.get('http://data.fixer.io/api/latest?    access_key=[yourAccessKey]&format=1');
}

داده‌ای این پاسخ، در response.data.rates در دسترس هستند؛ پس ما آن را در یک متغیر درست زیر پاسخ قرار می‌دهیم:

const rate = response.data.rates;

با توجه به این که همه چیز از یورو تبدیل می‌شود، در اینجا ما یک متغیر به نام euro‌ می‌سازیم که برابر با ۱ تقسیم بر ارزشی که می‌خواهیم از آن تبدیل کنیم، خواهد بود.

const euro = 1 / rate[fromCurrency];

در آخر، برای دریافت یک نرخ تبدیل، ما می‌توانیم یوروها را ضرب در ارزی که می‌خواهیم به آن تبدیل کنیم نماییم:

const exchangeRate = euro * rate[toCurrency];

در نهایت، تابع باید چنین ظاهری داشته باشد:

دومین تابع - دریافت داده‌های ارز به صورت همگام

ما یک تابع ناهمگام خواهیم ساخت که قرار است currencyCode را به عنوان یک آرگومان بگیرد:

const getCountries = async (currencyCode) => {}

همانطور که پیش‌تر دیدیم، ما می‌خواهیم داده‌ها را دریافت کرده و آن‌ها را به یک متغیر اختصاص دهیم:

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

سپس ما داده مورد نظر را map‌ کرده و برای هر کدام country.name را بر می‌گردانیم:

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

در نهایت، تابع ما باید چنین ظاهری داشته باشد:

سومین و آخرین تابع - ادغام آن‌ها

ما یک تابع ناهمگام خواهیم ساخت که قرار است fromCurrency، toCurrency و مقدار را به عنوان یک آرگومان بگیرد:

const convert = 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‌ برای مدیریت خطاها

ما باید تمام منطق خود را در try جمع کرده و اگر خطایی بود، آن را دریافت کنیم:

const getExchangeRate = async (fromCurrency, toCurrency) => {
  try {
    const response = await axios.get('http://data.fixer.io/api/latest?access_key=f68b13604ac8e570a00f7d8fe7f25e1b&format=1');

    const rate = response.data.rates;
    const euro = 1 / rate[fromCurrency];
    const exchangeRate = euro * rate[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}`);
  }
};

و با توجه به این که سومین تابع با چیزی که توابع اول و دوم فراهم کردند کار می‌کند، نیازی به بررسی برای خطاها نیست.

در آخر، ما می‌توانیم تابع را فراخوانی کرده و داده‌ها را دریافت کنیم:

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

خروجی‌ای که قرار است دریافت کنیم:

همین!

شما به انتهای راه رسیدید. اگر در طی مسیر در جایی گیر کردید، می‌توانید کد کامل را در این مخزن بررسی کنید.

مقالات دیگر درباره Async / Await:

منبع

چه امتیازی به این مقاله می دید؟
خیلی بد
بد
متوسط
خوب
عالی

دیدگاه‌ها و پرسش‌ها

برای ارسال دیدگاه لازم است، ابتدا وارد سایت شوید.

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

آفلاین
user-avatar
عرفان کاکایی @er79ka
دنبال کردن

گفتگو‌ برنامه نویسان

بخشی برای حل مشکلات برنامه‌نویسی و مباحث پیرامون آن وارد شو