بررسی توابع AsyncAwait در جاوااسکریپت

مقدمه
Promiseها راه سادهتری برای مدیریت عملیات asynchronous در جاوااسکریپت فراهم کردند و باعث شدند بتوانیم کدها را بهصورت ترتیبی و قابلفهمتر بنویسیم. از آنجایی که ذهن انسان برای مدیریت همزمانیهای پیچیده طراحی نشده، این ویژگی کمک بزرگی محسوب میشود.
ویژگی async/await که در ES2017 (یا ES8) معرفی شد، کار را حتی سادهتر کرد. با استفاده از آن میتوان کدی نوشت که ظاهری کاملاً synchronous دارد، در حالی که در پشت صحنه عملیات asynchronous انجام میشود.
در واقع، کاری که async/await انجام میدهد را میتوان با ترکیب Promiseها و Generatorها هم پیادهسازی کرد، اما async/await بدون نیاز به کدهای اضافی و پیچیده این قابلیت را فراهم میکند.
مثال ساده
در مثال زیر، ابتدا تابعی داریم که یک Promise برمیگرداند و بعد از ۲ ثانیه مقدار 🤡 را resolve میکند:
function scaryClown() {
return new Promise(resolve => {
setTimeout(() => {
resolve('🤡');
}, 2000);
});
}
سپس یک تابع async تعریف میکنیم:
async function msg() {
const msg = await scaryClown();
console.log('Message:', msg);
}
msg();
خروجی بعد از ۲ ثانیه:
Message: 🤡
await چیست؟
کلمه کلیدی await برای صبر کردن روی resolve یا reject شدن یک Promise استفاده میشود.
نکته مهم:
awaitفقط داخل توابعasyncقابل استفاده است.
اجرای چند مرحله async
مثال زیر قدرت واقعی async/await را بهتر نشان میدهد:
function who() {
return new Promise(resolve => {
setTimeout(() => {
resolve('🤡');
}, 200);
});
}
function what() {
return new Promise(resolve => {
setTimeout(() => {
resolve('lurks');
}, 300);
});
}
function where() {
return new Promise(resolve => {
setTimeout(() => {
resolve('in the shadows');
}, 500);
});
}
تابع async:
async function msg() {
const a = await who();
const b = await what();
const c = await where();
console.log(`${a} ${b} ${c}`);
}
msg();
خروجی:
🤡 lurks in the shadows
بعد از حدود ۱ ثانیه.
اجرای موازی با Promise.all
در مثال قبلی، هر عملیات منتظر اتمام عملیات قبلی میماند. اگر بخواهیم همه عملیات همزمان اجرا شوند، از Promise.all استفاده میکنیم:
async function msg() {
const [a, b, c] = await Promise.all([
who(),
what(),
where()
]);
console.log(`${a} ${b} ${c}`);
}
اکنون خروجی بعد از حدود ۵۰۰ میلیثانیه نمایش داده میشود.
Promise.all چگونه کار میکند؟
متد Promise.all:
- چند Promise را بهصورت همزمان اجرا میکند.
- بعد از resolve شدن همه Promiseها، آرایهای از نتایج برمیگرداند.
توابع async همیشه Promise برمیگردانند
مثال:
async function hello() {
return 'Hello Alligator!';
}
const b = hello();
console.log(b);
خروجی:
Promise { ... }
چون تابع async همیشه Promise برمیگرداند.
دریافت مقدار Promise
hello().then(x => console.log(x));
خروجی:
Hello Alligator!
انواع مختلف تعریف async
تابع معمولی
async function msg() {
}
Function Expression
const msg = async function() {
}
Arrow Function
const msg = async () => {
}
مدیریت خطاها با try…catch
یکی از بهترین ویژگیهای async/await مدیریت ساده خطاست.
مثال:
function yayOrNay() {
return new Promise((resolve, reject) => {
const val = Math.round(Math.random());
val
? resolve('Lucky!!')
: reject('Nope 😠');
});
}
استفاده:
async function msg() {
try {
const msg = await yayOrNay();
console.log(msg);
} catch(err) {
console.log(err);
}
}
مزیت مهم
برخلاف callbackها یا chainهای طولانی Promise، مدیریت خطا در async/await بسیار شبیه کدنویسی عادی و synchronous است.
مدیریت خطا با catch
چون async همیشه Promise برمیگرداند:
msg().catch(err => console.log(err));
گرفتن خطاهای Runtime
function caserUpper(val) {
return new Promise(resolve => {
resolve(val.toUpperCase());
});
}
تابع async:
async function msg(x) {
try {
const msg = await caserUpper(x);
console.log(msg);
} catch(err) {
console.log('Ohh no:', err.message);
}
}
اجرا:
msg('Hello'); // HELLO
msg(34); // Error
خروجی:
Ohh no: val.toUpperCase is not a function
استفاده از Async/Await با Fetch API
متد fetch چون Promise-based است، گزینهای عالی برای async/await محسوب میشود.
async function fetchUsers(endpoint) {
const res = await fetch(endpoint);
let data = await res.json();
data = data.map(user => user.username);
console.log(data);
}
استفاده:
fetchUsers('https://jsonplaceholder.typicode.com/users');
پشتیبانی مرورگرها
طبق آمار سال ۲۰۲۰:
- حدود ۹۴٪ مرورگرها از async/await پشتیبانی میکنند.
- مرورگرهای قدیمی مثل IE11 و Opera Mini از آن پشتیبانی نمیکنند.
جمعبندی
قبل از async/await، کدهای asynchronous در جاوااسکریپت معمولاً به چیزی معروف به:
Callback Hell
تبدیل میشدند؛ یعنی زنجیرهای پیچیده از callbackها که خواندن و نگهداری آنها سخت بود.
اما async/await باعث شد:
- کدها خواناتر شوند
- مدیریت خطا سادهتر شود
- ساختار کدها شبیه synchronous programming باشد
- توسعه و دیباگ راحتتر شود
امروزه async/await یکی از مهمترین مفاهیم مدرن جاوااسکریپت محسوب میشود و تقریباً در تمام پروژههای حرفهای استفاده میشود.
از همراهی شما با پارمین کلود سپاسگزاریم.




