فصل ۱۹: برنامهنویسی غیرهمزمان (Asynchronous) در جاوااسکریپت

۱. غیرهمزمان یعنی چه؟
فرض کن یک آشپز داری که میخواهد برایت غذا درست کند. وقتی آشپز غذا را میگذارد روی اجاق تا بجوشد، میرود کارهای دیگرش را هم انجام میدهد. منتظر نمیماند تا فقط غذا بپزد و هیچ کار دیگری نکند.
کامپیوترها هم همین کار را میکنند: اگر باید منتظر یک کار زمانبر باشند (مثل: خواندن فایل یا درخواست به اینترنت)، نمیایستند و بقیه برنامه را اجرا میکنند.
در جاوااسکریپت، این تکنیک به اسم “غیرهمزمان” یا asynchronous شناخته میشود.
۲. Callback چیست؟
Callback در اصل یعنی: «بیا بعداً این کار را انجام بده!»
مثال واقعی: سفارش پیتزا!
- تو به رستوران زنگ میزنی و سفارشت رو میدی.
- اپراتور میگه: شمارهتو بده، وقتی آماده شد تماس میگیرم (= کالبک!)
- تو میری کار خودت رو میکنی تا سفارشت آماده بشه.
- وقتی آماده شد، اپراتور باهات تماس میگیره (تابع کالبک اجرا میشه).
مثال کد:
function sayHello(name) {
console.log('سلام، ' + name + '!');
}
function getNameAndGreet(callback) {
let name = prompt("اسمت چیه؟");
callback(name);
}
getNameAndGreet(sayHello);
در اینجا، تابع sayHello به عنوان کارِ بعداً-executed داده شده.
۳. مشکل Callbackها: جهنم Callback (Callback Hell)
گاهی اوقات باید کارهای غیرهمزمان زیادی پشتسر هم انجام بدهی. مثلاً اول باید نام کاربر را بپرسی، بعد به سرور بفرستی، بعد جواب را نمایش بدهی و …
اگر همه این کارها را با Callback انجام بدی، کدت شبیه نردبان میشود و فهمش سخت میشود. به این میگویند Callback Hell:
getData(function(data1) {
getMoreData(data1, function(data2) {
getEvenMoreData(data2, function(data3) {
// و همینطور...
});
});
});
۴. Promise چیست؟ (قول! سادهتر از کالبک)
Promise توی جاوااسکریپت یعنی «قول دادن» که ممکن است در آینده کار موفق باشد (fulfilled/resolved) یا شکست بخورد (rejected).
- میتوانی بگویی:
“قول میدم اگر سفارش آماده شد بهت خبر بدم (resolve)، اگر دلیوری گم شد بهت خبر میدم (reject!)”
ساخت یک Promise ساده:
let pizzaOrder = new Promise(function(resolve, reject) {
let pizzaReady = true; // فرض کن پیتزا آماده بشه
if (pizzaReady) {
resolve("پیتزا آمادهست! بیا بردار.");
} else {
reject("اوه! پیتزا نسوخت شد!");
}
});
// استفاده از Promise
pizzaOrder.then(function(message) {
// اگر موفق شود
alert(message);
}).catch(function(error) {
// اگر شکست بخورد
alert(error);
});
مزیت: میتوان راحتتر چند کار را پشت سر هم انجام داد و کد تمیزتر میشود.
۵. Async و Await — زندگی راحتتر!
Async/Await کاری میکند که بنویسی کدت انگار دستوری است، ولی پشتصحنه غیرهمزمان اجرا شود.
مثال خیلی ساده:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function runOrder() {
console.log("سفارش ثبت شد.");
await wait(2000); // دو ثانیه منتظر باش!
console.log("پیتزا آماده شد!");
}
runOrder();
توضیح:
- “async” میگه این فانکشن قراره با کارهای غیرهمزمان سر و کار داشته باشه.
- “await” توی همون تابع یعنی: اینجا وایسا تا این کار تموم بشه، بعد برو خط بعد.
جمعبندی خیلی ساده:
- Callback: «هر وقت کارت تموم شد اینو اجرا کن»
- Promise: «بهت قول میدم که یه کاری رو انجام بدم یا شکست میخوره»
- Async/Await: «کد غیرهمزمان رو طوری بنویس که شبیه کد عادی/خطی باشه و خوندنش ساده باشه.»
تمرین قدمبهقدم:
- یک تابع غیرهمزمان ساده با کالبک بنویس:
function doLater(callback) {
setTimeout(function() {
callback("کارم تموم شد!");
}, 1000);
}
doLater(function(result) {
alert(result);
});
- یک Promise ساده که بعد از ۲ ثانیه یک پیغام بده:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
delay(2000).then(() => alert("۲ ثانیه صبر کردی!"));
- یک تابع async/await که بعد از ۱ ثانیه پیام چاپ کند:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function main() {
await wait(1000);
alert("سلام! من با await صبر کردم.");
}
main();