یکی از مفاهیم نسبتا سخت و پیچیده که بیشتر اوقات باعث گیج شدن و سردرگمی برخی از برنامه نویسان می شود مفهوم غیرهمزمان یا Asynchronous
می باشد .
در اکثر مصاحبه ها دیده می شود که این مفهوم مورد سوال قرار میگیرد، من قصد دارم که این مبحث را یکبار باز کرده تا کسانی که میخواهند درکی از برنامه نویسی ناهمزمان داشته باشند کمکی کرده باشم.
این بخش سه قسمت دارد :
asynchronous JS
Promises
async/await
قبل شروع مفاهیم بالا باید این سوال را در ابتدا از خود بپرسیم که چرا ما به برنامه نویسی ناهمزمان اهمیت می دهیم؟
موضوع غیر همزمان بودن در دو بخش سرور و کلاینت مورد اهمیت می باشد ولی در این مقاله بیشتر بر روی کلاینت تمرکز میکنم ولی در اینده حتما برای باز کردن مباحث بیشتر مایلم آن را به بخش سرور ببرم.
ابتدا باید بدانیم که جاوا اسکریپت همیشه همزمان و تک رشته ای است. به عبارت دیگر ، هنگامی که یک بلوک کد اجرا می شود، هیچ بلوک دیگری از کد اجرا نمی شود.
همانطور که در بالا مشاهده می کنید کنسول مقادیر را به ترتیب چاپ می کند.
برنامه های که با جاوا اسکرپیت نوشته می شوند معمولا تحت وب و رویداد محور هستن. به عبارت دیگر، جاوا اسکریپت تا زمانی که کاربر بر روی چیزی کلیک نکند یا ضربه نزد رویدادی اتفاق نمی افتد (سمت مشتری). در بخش دیگر که سرور قرار دارد و مبتنی بر JS
می باشد منتظر می باشد که در سمت کلاینت از طریق اینترنت درخواستی به آن ارسال شود.
ما از JS
ناهمزمان در مواردی مانند واکشی یا دسترسی به نوعی منبع از API
شخص ثالث استفاده می کنیم.
شما تصور کنید که تصویری با حجم زیادی از سمت سرور باید از بالای سایت شما بارگذاری شود، اگر سرور برای بارگذاری کردن این تصویر باید منتظر بمانند تا فرایند آن از سمت سرور به پایان برسد و بعد به سراغ بارگذاری بقیه محتوای سایت برود حتما این موضوع برای کاربر های شما جالب نمی باشد و عملکرد سایت شما را پایین می آرود زیرا نمی دانید این فرایند قرار است چقد طول بکشد.!
برنامه نویسی ناهمزمان توسط Callback
ها
قبل از اینکه وارد Promise
ها بشویم اساسی ترین مفهومی که باید بفهمیم فراخوانی می باشد (گذراندن یک تابع دیگر در یک تابع و هنگامی که شرایطی برآورده می شود یا رویدادی رخ می دهد، فراخوانی می شود).
همچنین روش قدیمی مدیریت برنامه نویسی ناهمزمان قبل از معرفی Promise
در ES6
است. اما برخی از این callback
ها هنوز معمولاً بدون promise
دیده می شوند.
اولین آرگومان ()setTimeOut
یک تابع callback
و آرگومان دوم یک فاصله زمانی است که بر حسب میلی ثانیه اندازه گیری می شود.
معرفی Promise
ها
Promises
در ES6
برای ساده سازی برنامه نویسی ناهمزمان یا نامتقارن معرفی شدند. در این بخش به موارد زیر می پردازیم:
- چرا
promise
ها معرفی شدند؟ (هشدار خرابکاری: مشکل در فراخوانی و شلوغیcallback
ها) - تمام
promise
ها به ما قول میدهند که پاسخ را در سه حالت برگرداند : (then
,catch
,finally
)
حال باید مثالی بزنیم شما تصور کنید در کافه ای میخواهید قهوه ای سفارش دهید در سه مرحله باید این فرایند اتفاق یبفتد ابتدا باید تصمیم بگیرید که چه نوع قهوه ای می خواهید، سپس سفارش خود را با باریستا ثبت کنید، سپس قهوه خود را دریافت کنید، آخرین و مهمترین، نحوه فراخوانی مجدد ظاهر می شود (اشاره به سند MDN در promise
) :
chooseCoffee(function(order) {
placeOrder(order, function(coffee) {
drinkCoffee(coffee);
}, failureCallback);
}, failureCallback);
ظاهر بسیار کثیفی دارد! این همان چیزی است که اغلب به عنوان callbacks-hell
یا جهنم فراخوانی ها نامیده می شود. promise
ها اجازه می دهند این نوع callback
های تو در تو به عنوان زنجیره promise
مجدداً بیان شوند، که در ادامه مقاله بیشتر به آنها می پردازیم.
قاعد کلی تعریف promise
به شکل زیر می باشد :
let promise = new Promise(function(resolve, reject) {
// executor
});
آرگومان ها resolve
و reject
در callback
آبجکت promise
که توسط جاوا اسکریپت ارائه شده است فراخوانی می شوند.
در اینجا شما با سه مفهوم رو به رو می شوید که به شرح ذیل می باشد :
pending
: هنگامی کهpromise
ایجاد می شود، در حالت موفقیت یا شکست قرار می گیرد.resolved
: هنگامی کهpromise
بازگشت داده می شود و در حالت حل شده قرار می گیرد.fulfilled
: هنگامی کهpromise
با موفقیت حل می شود مقدار را برمیگرداند که میتوان با زنجیره زدنthen
به مقدار آن دسترسی پیدا کرد.rejected
: هنگامی کهpromise
بدون موفقیت حل می شود که یک پیغام خطا را برای رد شدن آن برمی گرداند که با زنجیره زدنcatch
به مقدار آن می توان دسترسی پیدا کرد.
شکل زیر نمایانگر فرایند اجرای promise
می باشد:
قطعه کد زیر یک promise
کامل را با تمام حالت ها نمایش میدهد :
let example = () => {
return new Promise(function(resolve, reject) => {
let value = function1();
if (job success) {
resolve(value);
} else (job unsuccessful) {
reject(console.log("something's wrong!! :("));
}
}).then(function(value)) {
// success
return nextFunction(value);
}).catch(rejectFunction);
}
مفهوم async
/ awiat
کلمات کلیدی async
و await
در ES2018
برای کاهش دیگر تکرارات و حل محدودیت "در شکستن زنجیره" در promise
ها معرفی شد.
بیایید تفاوت بین Promises
و async/await
را ببینیم!
promise
:
const promise = () => {
return new Promise(resolve => {
setTimeout(() => resolve("done!"), 1000);
})
};
async/await
:
const promise = async () => {
console.log(await promiseAsync());
};
در نتیجه هنگامی که از async/await
استفاده می شود، then/catch
به ندرت استفاده می شود. چرا که در درون خود مقادیر به صورت مستفیم به promise
مورد نظر برمیگردند و دیگر نیازی به نوشتن زنجیره ای برای آنها نیست .
نتیجه گیری
تمام فرایند غیرهمزمان در بین همین مفاهیم هست که برایتان توضیح دادم و بسیار مبحث مهمی در برنامه نویسی جاوا اسکریپت می باشد و برای درک بهتر باید به سمت مثال علمی بروید، در این مقاله من میخواستم تا حد امکان خلاصه توضیح بدم ولی این مباحث بسیار نکات مهمی را دارا می باشند که هنوز جای بحث و باز شدن دارند، امیدوارم این مقاله برای شما مفید واقعه شده باشد.