آموزش Async Await در JavaScript با مثال عملی | راهنمای کامل مبتدی تا پیشرفته

آموزش Async Await در JavaScript با مثال عملی | راهنمای کامل مبتدی تا پیشرفته

  • سطح : متوسط
  • مطالعه : 11 دقیقه
  • 120

 آموزش Async Await در JavaScript با مثال عملی

آموزش Async Await یکی از مهم‌ترین مباحث جاوااسکریپت مدرن است که هر برنامه‌نویس وب باید آن را یاد بگیرد. در این مقاله با مثال‌های واقعی و پروژه‌های کاربردی یاد می‌گیریم Async Await چیست و چگونه از آن استفاده کنیم.

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

برای مثال فرض کنید کاربر روی دکمه «مشاهده اطلاعات» کلیک می‌کند و برنامه باید اطلاعات را از یک API دریافت کند. دریافت این اطلاعات ممکن است چند ثانیه زمان ببرد. سؤال اینجاست:

آیا باید کل برنامه تا دریافت پاسخ متوقف شود؟

پاسخ منفی است.

جاوااسکریپت برای حل این مشکل از مفهومی به نام Asynchronous Programming یا برنامه‌نویسی ناهمگام استفاده می‌کند.

درک این مفهوم یکی از مهم‌ترین قدم‌ها برای تبدیل شدن به یک توسعه‌دهنده حرفه‌ای JavaScript است.

در این مقاله قصد داریم یکی از مهم‌ترین ابزارهای برنامه‌نویسی ناهمگام یعنی Async Await را به صورت کامل و با مثال‌های واقعی یاد بگیریم.

تفاوت اجرای همگام و ناهمگام در JavaScript

برنامه‌نویسی ناهمگام (Asynchronous) چیست؟

قبل از اینکه وارد Async Await شویم، ابتدا باید بدانیم برنامه‌نویسی ناهمگام چیست.

به کد زیر توجه کنید:


console.log("شروع برنامه");

console.log("دریافت اطلاعات");

console.log("پایان برنامه");

خروجی:

  • شروع برنامه
  • دریافت اطلاعات
  • پایان برنامه

در این مثال دستورات به ترتیب و خط به خط اجرا می‌شوند.به این نوع اجرا، اجرای همگام (Synchronous) گفته می‌شود.اما در دنیای واقعی همیشه همه چیز به این سادگی نیست.

فرض کنید برنامه باید اطلاعات را از یک سرور دریافت کند.دریافت اطلاعات ممکن است چند ثانیه طول بکشد.

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

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

 

یک مثال ساده:


console.log("شروع");

setTimeout(() => {
console.log("اطلاعات دریافت شد");
}, 3000);

console.log("پایان");

خروجی:

  • شروع
  • پایان
  • اطلاعات دریافت شد

همان‌طور که مشاهده می‌کنید، جاوااسکریپت منتظر پایان setTimeout نمی‌ماند و اجرای برنامه را ادامه می‌دهد, این دقیقاً مفهوم برنامه‌نویسی ناهمگام است.

چرا یادگیری Async Await مهم است؟

یکی از سؤالاتی که دانشجویان دوره‌های جاوااسکریپت معمولاً مطرح می‌کنند این است:

«من HTML و CSS را یاد گرفته‌ام، برای ورود به پروژه‌های واقعی باید روی چه مباحثی تمرکز کنم؟»

پاسخ من تقریباً همیشه یکسان است:

پس از یادگیری مبانی JavaScript باید مفاهیم زیر را به خوبی درک کنید:

  • Promise
  • Async Await
  • Fetch API

تقریباً تمام پروژه‌های مدرن جاوااسکریپت از این سه مفهوم استفاده می‌کنند.

اگر قصد دارید در آینده با React، Vue یا حتی APIهای Laravel کار کنید، یادگیری Async Await ضروری است.

Promise چیست؟

قبل از معرفی Async Await باید با Promise آشنا شویم.

در ساده‌ترین تعریف، Promise یک وعده برای ارائه نتیجه در آینده است.

فرض کنید از یک رستوران سفارش غذا داده‌اید.

در لحظه سفارش، غذا آماده نیست.

اما رستوران به شما قول می‌دهد که پس از آماده شدن غذا آن را تحویل دهد.

Promise نیز دقیقاً همین رفتار را دارد.

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

به مثال زیر توجه کنید:

javascript


const promise = new Promise((resolve, reject) => {

    setTimeout(() => {

        resolve("اطلاعات با موفقیت دریافت شد");

    }, 2000);

});

در این مثال Promise پس از دو ثانیه نتیجه را برمی‌گرداند.

برای دریافت نتیجه از then استفاده می‌کنیم:

javascript


promise.then(result => {
    console.log(result); 
});

خروجی:

  • اطلاعات با موفقیت دریافت شد

مشکل Promiseهای تو در تو

Promiseها ابزار بسیار قدرتمندی هستند اما در پروژه‌های بزرگ یک مشکل ایجاد می‌کنند.

به مثال زیر نگاه کنید:

javascript


getUser()
   .then(user => {
     return getOrders(user.id);
   }) 
   .then(orders => { 
       return getPayments(orders); 
  }) 
  .then(payments => { 
    console.log(payments); 
  });

کد بالا کاملاً صحیح است.

اما حالا تصور کنید به جای سه مرحله، ده مرحله داشته باشیم.

در چنین شرایطی خواندن و نگهداری کد دشوار خواهد شد.

به همین دلیل Async Await معرفی شد تا نوشتن کدهای ناهمگام ساده‌تر و خواناتر شود.

مفهوم Promise در جاوااسکریپت

Async Await چیست؟

Async Await قابلیتی در JavaScript است که روی Promiseها ساخته شده است.

این نکته بسیار مهم است.

یکی از اشتباهات رایجی که در بین دانشجویان مشاهده می‌کنم این است که تصور می‌کنند Async Await جایگزین Promise است.

در حالی که Async Await بدون Promise هیچ معنایی ندارد.

در واقع Async Await فقط یک روش ساده‌تر و خواناتر برای کار کردن با Promiseها است.

به کمک آن می‌توانیم کدهای ناهمگام را تقریباً شبیه کدهای عادی و خطی بنویسیم.

در بخش بعدی اولین مثال عملی Async Await را بررسی خواهیم کرد و خواهید دید که چگونه کدهای پیچیده Promise به چند خط ساده و قابل فهم تبدیل می‌شوند.

 

اولین مثال عملی Async Await

حالا که با مفهوم Promise آشنا شدیم، زمان آن رسیده که ببینیم Async Await چگونه کدهای ما را ساده‌تر می‌کند.

ابتدا همان مثال Promise را دوباره مشاهده کنید:


  function getUser() {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve({
          id: 1,
          name: "Vahid",
        });
      }, 2000);
    });
  }
  getUser().then((user) => {
    console.log(user);
  });

این کد کاملاً صحیح است و هیچ مشکلی ندارد.

اما اگر پروژه بزرگ‌تر شود و چندین عملیات پشت سر هم داشته باشیم، تعداد then ها افزایش پیدا می‌کند و خواندن کد دشوار می‌شود.

همان مثال را با Async Await بازنویسی می‌کنیم:


  async function showUser() {
    const user = await getUser();
    console.log(user);
  }
  showUser();

در نگاه اول شاید تفاوت زیادی مشاهده نکنید.

اما نکته مهم اینجاست که کد بالا تقریباً شبیه برنامه‌نویسی عادی نوشته شده است.

به همین دلیل بسیاری از توسعه‌دهندگان آن را خواناتر و قابل نگهداری‌تر می‌دانند.


async و await هر کدام چه کاری انجام می‌دهند؟

یکی از اشتباهات رایج دانشجویان این است که تصور می‌کنند async و await یک مفهوم واحد هستند.

در حالی که هر کدام وظیفه مشخصی دارند.

کلمه async

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


async function getData() { 
  
}

در واقع هر تابع async به صورت خودکار یک Promise برمی‌گرداند.


کلمه await

کلمه await به جاوااسکریپت می‌گوید:

“منتظر بمان تا نتیجه Promise آماده شود.”


const user = await getUser();

در اینجا اجرای تابع تا زمان آماده شدن نتیجه متوقف می‌شود.

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

این نکته بسیار مهم است.


Async Await در کنار Fetch API

در پروژه‌های واقعی بیشترین کاربرد Async Await را معمولاً در کنار Fetch API مشاهده می‌کنیم.

فرض کنید می‌خواهیم اطلاعات کاربران را از یک API دریافت کنیم.


  async function getUsers() {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    const users = await response.json();
    console.log(users);
  }

اجازه دهید قدم به قدم بررسی کنیم چه اتفاقی رخ می‌دهد.

ابتدا Fetch درخواست را به سرور ارسال می‌کند.

سپس await منتظر دریافت پاسخ می‌ماند.

بعد از دریافت پاسخ، متد json اجرا می‌شود.

در نهایت داده‌ها به صورت آرایه یا آبجکت جاوااسکریپت در اختیار ما قرار می‌گیرند.

اگر دانشجویان تازه‌کار این بخش را خوب درک کنند، یادگیری React و Vue برایشان بسیار ساده‌تر خواهد شد.

استفاده از Async Await در Fetch API


مدیریت خطاها با Try Catch

تا اینجا فرض کردیم همه چیز طبق انتظار پیش می‌رود.

اما در دنیای واقعی همیشه این‌طور نیست.

ممکن است:

  • اینترنت کاربر قطع شود.
  • سرور از دسترس خارج شود.
  • API خطا برگرداند.
  • پاسخ نامعتبر باشد.

به همین دلیل باید خطاها را مدیریت کنیم.


  async function getUsers() {
    try {
      const response = await fetch("/users");
      const users = await response.json();
      console.log(users);
    } catch (error) {
      console.error(error);
    }
  }

در این مثال اگر هر خطایی رخ دهد، برنامه متوقف نمی‌شود و خطا داخل catch مدیریت خواهد شد.


چرا مدیریت خطا اهمیت دارد؟

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

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

بعد از پیاده‌سازی Try Catch و نمایش پیام مناسب، تعداد درخواست‌های پشتیبانی به شکل محسوسی کاهش پیدا کرد.

این مثال نشان می‌دهد مدیریت خطا فقط یک موضوع فنی نیست؛ مستقیماً روی تجربه کاربری تأثیر می‌گذارد.


اشتباهات رایج دانشجویان هنگام استفاده از Async Await

در طول سال‌های تدریس چند اشتباه را بارها مشاهده کرده‌ام.

اشتباه اول

استفاده از await خارج از تابع async


const users = await getUsers();

کد بالا خطا ایجاد می‌کند.

زیرا await فقط داخل توابع async قابل استفاده است.


اشتباه دوم

فراموش کردن await


const users = getUsers();
 console.log(users);

در این حالت به جای اطلاعات کاربران، یک Promise دریافت خواهید کرد.


اشتباه سوم

تصور اینکه Async Await جایگزین Promise است

این یکی از رایج‌ترین سوءتفاهم‌هاست.

Async Await روی Promise ساخته شده است و بدون Promise نمی‌تواند کار کند.

در واقع Async Await فقط روشی خواناتر برای استفاده از Promiseهاست.

یک مثال واقعی از Async Await در پروژه‌های Laravel

تا اینجا مثال‌های آموزشی را بررسی کردیم، اما اجازه دهید ببینیم Async Await در پروژه‌های واقعی چه کاربردی دارد.

فرض کنید در یک فروشگاه اینترنتی، کاربر وارد صفحه محصول شده است. در لحظه ورود به صفحه باید چندین اطلاعات مختلف دریافت شوند:

  • اطلاعات محصول
  • نظرات کاربران
  • محصولات مرتبط
  • وضعیت موجودی انبار

اگر این اطلاعات به شکل مناسبی دریافت نشوند، صفحه با تأخیر نمایش داده می‌شود و تجربه کاربری ضعیفی ایجاد خواهد شد.

در چنین شرایطی معمولاً از Async Await برای مدیریت درخواست‌های API استفاده می‌کنیم.

برای مثال:


  async function loadProductPage(productId) {
    const productResponse = await fetch(`/api/products/${productId}`);
    const commentsResponse = await fetch(`/api/products/${productId}/comments`);
    const product = await productResponse.json();
    const comments = await commentsResponse.json();
    console.log(product);
    console.log(comments);
  }

در این مثال اطلاعات محصول و نظرات کاربران از API لاراول دریافت می‌شوند و سپس در صفحه نمایش داده می‌شوند.

امروزه تقریباً تمام پنل‌های مدیریت مدرن، فروشگاه‌های اینترنتی و نرم‌افزارهای تحت وب از الگوهای مشابه استفاده می‌کنند.


تفاوت Promise و Async Await

یکی از سوالاتی که تقریباً در هر دوره آموزشی مطرح می‌شود این است:

«بالاخره از Promise استفاده کنیم یا Async Await؟»

پاسخ کوتاه این است:

هر دو.

در واقع Async Await جایگزین Promise نیست، بلکه روش ساده‌تر و خواناتری برای کار کردن با Promiseها است.

برای درک بهتر به جدول زیر توجه کنید:

asyncwait دربرابر promise

اگر پروژه ساده‌ای دارید، استفاده از Promise کاملاً کافی است.

اما در پروژه‌های بزرگ و حرفه‌ای معمولاً Async Await انتخاب بهتری خواهد بود.


اجرای همزمان چند درخواست با Promise.all

یکی از نکات حرفه‌ای که بسیاری از برنامه‌نویسان تازه‌کار از آن اطلاع ندارند، استفاده از Promise.all است.

فرض کنید باید اطلاعات سه API مختلف را دریافت کنید.

روش اشتباه:


  const users = await getUsers();
  const products = await getProducts();
  const comments = await getComments();

در این حالت درخواست‌ها یکی پس از دیگری اجرا می‌شوند.

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


  const [users, products, comments] = await Promise.all([ getUsers(), getProducts(), getComments() ]);

این روش در بسیاری از پروژه‌ها باعث افزایش سرعت بارگذاری صفحات می‌شود.


بهترین روش‌های استفاده از Async Await

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

۱. همیشه خطاها را مدیریت کنید

هرگز فرض نکنید اینترنت کاربر یا سرور همیشه در دسترس است.

همیشه از Try Catch استفاده کنید.


۲. از Await غیرضروری استفاده نکنید

برخی برنامه‌نویسان تقریباً قبل از هر خطی از Await استفاده می‌کنند.

این کار می‌تواند سرعت اجرای برنامه را کاهش دهد.


۳. نام‌گذاری مناسب داشته باشید

به جای نام‌های مبهم:


const data = await getData();

از نام‌های واضح‌تر استفاده کنید:


const users = await getUsers();

۴. ابتدا Promise را یاد بگیرید

یکی از اشتباهات رایج دانشجویان این است که مستقیماً سراغ Async Await می‌روند.

تجربه نشان داده است دانشجویانی که ابتدا Promise را به خوبی یاد می‌گیرند، Async Await را بسیار سریع‌تر درک می‌کنند.


جمع‌بندی

Async Await یکی از مهم‌ترین قابلیت‌های JavaScript مدرن است و تقریباً در تمام پروژه‌های امروزی مورد استفاده قرار می‌گیرد.

در این مقاله یاد گرفتیم:

  • برنامه‌نویسی ناهمگام چیست
  • Promise چه مشکلی را حل می‌کند
  • Async Await چگونه کار می‌کند
  • چگونه با Fetch API ترکیب می‌شود
  • چگونه خطاها را مدیریت کنیم
  • چه اشتباهاتی را نباید مرتکب شویم

اگر قصد دارید در آینده با React، Vue، Node.js یا APIهای Laravel کار کنید، آموزش Async Await یکی از اولین مهارت‌هایی است که باید روی آن مسلط شوید.
پیشنهاد می‌کنم بعد از مطالعه این مقاله، حتماً روی چند پروژه کوچک تمرین کنید و سپس سراغ Fetch API و کار با APIهای واقعی بروید.


سوالات متداول

Async Await چیست؟

Async Await قابلیتی در JavaScript است که امکان نوشتن کدهای ناهمگام به شکلی ساده‌تر و خواناتر را فراهم می‌کند.


آیا Async Await جایگزین Promise است؟

خیر. Async Await بر پایه Promise ساخته شده و در واقع روش ساده‌تری برای استفاده از Promiseها ارائه می‌دهد.


آیا می‌توان بدون Promise از Async Await استفاده کرد؟

خیر. Async Await برای کار کردن به Promise نیاز دارد.


تفاوت Async و Await چیست؟

کلمه Async یک تابع را ناهمگام می‌کند و Await منتظر تکمیل Promise می‌ماند.


Async Await در چه پروژه‌هایی استفاده می‌شود؟

تقریباً در تمام پروژه‌های مدرن JavaScript، React، Vue، Node.js و همچنین ارتباط با APIهای Laravel مورد استفاده قرار می‌گیرد.


آیا Async Await سرعت برنامه را افزایش می‌دهد؟

خیر. Async Await باعث افزایش خوانایی و نگهداری بهتر کد می‌شود. بهبود سرعت بیشتر به نحوه مدیریت درخواست‌ها و استفاده صحیح از Promiseها بستگی دارد.


منابع بیشتر

READ MORE

منابع بیشتر

READ MORE
برای مطالعه بیشتر می‌توانید مستندات رسمی Async/Await را در سایت MDN
مطالعه کنید.
پرسش و پاسخ

اولین دیدگاه رو شما برای ما ارسال و کنید

کاربر گرامی : برای ارسال دیدگاه خود ابتدا باید در سایت لاگین نمایید.