آموزش جامع Async/Await در جاوااسکریپت


🎯 اهداف یادگیری

  • درک مفهوم asynchronous در جاوااسکریپت
  • آشنایی با مشکلات callback hell
  • یادگیری نحوه کار با Promise
  • تسلط بر استفاده از Async/Await برای کدنویسی تمیزتر

📌 برنامه‌نویسی Asynchronous چیست؟

در جاوااسکریپت، برخی عملیات مانند درخواست‌های شبکه یا خواندن فایل‌ها زمان‌بر هستند و اگر به صورت همزمان (synchronous) اجرا شوند، کل برنامه را مسدود می‌کنند:

javascript
// مثال کد synchronous (مسدودکننده)
const data = fetchDataFromServer(); // این خط تا دریافت داده کامل صبر می‌کند
console.log(data);

راه‌حل‌های Asynchronous:

  • Callbackها: تابعی که پس از اتمام عملیات فراخوانی می‌شود
  • Promiseها: شیءای که نتیجه آینده یک عملیات را نشان می‌دهد
  • Async/Await: سینتکسی برای کار با Promiseها به صورت خطی

📌 مشکل Callback Hell

استفاده بیش از حد از callbackها منجر به کدی غیرقابل خواندن می‌شود:

javascript
getUser(userId, function(user) {
getPosts(user, function(posts) {
getComments(posts[0], function(comments) {
console.log(comments);
});
});
});

معایب Callbackها:

  • خوانایی پایین: هرم‌های تو در تو (Callback Hell)
  • مدیریت خطا سخت: نیاز به بررسی خطا در هر سطح
  • جریان کنترل پیچیده: دنبال کردن ترتیب اجرا دشوار است

📌 معرفی Promiseها

Promiseها شیءهایی هستند که نشان‌دهنده تکمیل یا شکست یک عملیات ناهمزمان هستند:

javascript
const promise = new Promise((resolve, reject) => {
if (operationSuccessful) {
resolve("عملیات موفق بود!");
} else {
reject(new Error("عملیات شکست خورد"));
}
});
promise.then(result => {
console.log(result); // "عملیات موفق بود!"
}).catch(error => {
console.error(error); // "عملیات شکست خورد"
});

حالت‌های Promise:

  • pending: در حال انتظار (حالت اولیه)
  • fulfilled: عملیات با موفقیت انجام شد
  • rejected: عملیات با شکست مواجه شد

📌 معرفی Async/Await

Async/Await سینتکسی برای کار با Promiseها به صورت خطی و خوانا است:

javascript
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('خطا در دریافت داده:', error);
}
}
fetchData();

قوانین Async/Await:

  • async: تابعی که حاوی await است باید با async تعریف شود
  • await: فقط می‌تواند داخل توابع async استفاده شود
  • try/catch: برای مدیریت خطاها ضروری است
  • مقدار بازگشتی: تابع async همیشه یک Promise برمی‌گرداند

📌 مقایسه روش‌های مختلف

Callback Promise Async/Await
خوانایی پایین خوانایی متوسط خوانایی بالا
مدیریت خطا سخت مدیریت خطا با catch مدیریت خطا با try/catch
زنجیره‌کردن سخت زنجیره‌کردن با then کدنویسی خطی

📌 تمرین عملی

تابع زیر را که با Promise نوشته شده است، به Async/Await تبدیل کنید:

javascript
function getUserData(userId) {
return fetch(`https://api.example.com/users/${userId}`)
.then(response => response.json())
.then(data => {
console.log(data);
return data;
})
.catch(error => {
console.error('خطا در دریافت داده کاربر:', error);
});
}

راهنمای تمرین:

  1. تابع را با async تعریف کنید
  2. فراخوانی‌های then را با await جایگزین کنید
  3. مدیریت خطا را با try/catch انجام دهید

📌 نکات پیشرفته

  • Promise.all: برای اجرای چند Promise به صورت موازی
  • Promise.race: برای دریافت اولین Promise تکمیل شده
  • Async IIFE: برای اجرای فوری توابع async
  • Top-level Await: استفاده از await در ماژول‌های ES
javascript
// استفاده از Promise.all برای درخواست‌های موازی
async function fetchAllData() {
const [user, posts] = await Promise.all([
fetch('/user').then(r => r.json()),
fetch('/posts').then(r => r.json())
]);
console.log(user, posts);
}

📌 قدم بعدی

در درس بعدی با Fetch API در جاوااسکریپت آشنا خواهیم شد!