Promise به معنای قول دادن و پيمان بستن است. فرض كنيد به يكی از دوستانتان قول دادهايد كه آخر هفته با او به يكی از كافههای سطح شهر برويد. حال دو حالت وجود دارد. از آنجايی كه قرار است آخر هفته كه يك زمان در آينده است، اين كار انجام شود، احتمال دارد بتوانيد به قول خود پايبند باشيد، و احتمال دارد كاری برای شما پيش بيايد و نتوانيد به قول خود عمل كنيد. مفهوم promise در جاوا اسکریپت ، رفتاری مشابه به اين بحث دارد، كه در ادامه به آن میپردازيم.
قبل از پرداختن به هر موضوعی میخواهيم به پاسخ اين سوال بپردازيم، كه كاربرد Promise چيست؟
در جاوا اسكريپت Promise كاربردی مشابه callback function دارد. به این معنی که از Promise همانند callback function برای مدیریت کردن دستورات غیر همزمان یا asynchronous استفاده میکنیم. حال سوال پیش میآید که منظور از دستورات asynchronous چیست؟
پردازش کد در کامپیوترزبان جاوا اسکریپت یک زبان مفسری است. در زبانهای مفسری، اجرای کدها به صورت خط به خط است. همچنین جاوا اسکریپت یک زبان رویدادگرا نیز هست. به این معنی که زمانیکه در ترجمه خط به خط کدها مفسر به یک بخشی از کد برای مثال به یک تابع برخورد میکند که فرآیند دریافت پاسخ توسط تابع طولانی است، همزمان با اجرای آن بخش از کد، به خطهای بعدی برنامه رفته و آنها را اجرا میکند. زمانی که پاسخ از تابع زمانبر دریافت شد، برای اجرا باید منتظر اتمام اجرای کدهای جلوتر خود باشد. به نوعی وارد یک صف اجرا میشود که برای اجرا باید منتظر شود که به اول این صف برسد و سپس اجرا شود. به دو صورت زیر انجام میشود:
– Asynchronous یا پردازش ناهمگام (غیر همزمان): در این نوع پردازش، زمانی که پردازشگر شروع به پردازش میکند، بدون اینکه منتظر اتمام پردازش اول باشد، پردازش دوم را شروع میکند.
– synchronous یا پردازش همگام (Blocking): در این نوع پردازش، پردازشگر ابتدا پردازش اول را به طور کامل به پایان میرساند، سپس پردازش دوم را شروع میکند.
زبان جاوا اسکریپت یک زبان مفسری است. در زبانهای مفسری، اجرای کدها به صورت خط به خط است. همچنین جاوا اسکریپت یک زبان رویدادگرا نیز هست. به این معنی که زمانی که، در ترجمه خط به خط کدها مفسر به یک بخشی از کد برای مثال به یک تابع برخورد میکند. که فرآیند دریافت پاسخ توسط تابع طولانی است، همزمان با اجرای آن بخش از کد، به خطهای بعدی برنامه رفته و آنها را اجرا میکند. شرایطی را در نظر بگیرید، که در خواستی را به یک سرور ارسال کردهاید، تا اطلاعاتی را دریافت کنید، که در ادامه به آن اطلاعات احتیاج دارید، تا توابعی که تعریف کردهاید، از آن اطلاعات استفاده کنند. فرض کنید ارسال پاسخ از سمت سرور کمی طولانی شده است. میخواهیم کاری کنیم تازمانی که پاسخ سرور مشخص نشده است، کدهای بعدی اجرا نشود. راه حل چیست؟ راه حل این است، که یا از Promise یا از callback function استفاده کنیم.
توصیه میکنیم قبل از خواندن ادامهی مقاله، برای درک بهتر و آشنایی با callback function، مقالهی callback function چیست را مطالعه کنید.
پیشتر گفتیم کاربرد Promise همانند callback function است. حال کدام یک از این دو انتخاب بهتری است؟
قبل از اینکه Promise معرفی شود برای انجام چند وظیفهی غیر هم زمان از callback function استفادهی زیادی میشد. استفاده از callback functionها مشکلاتی نیز به همراه داشت، که یکی از این مشکلات این بود که در برخی موارد منجر به تولید کدی میشد، که مدیریت کردن و خطایابی آن بسیار مشکل بود و گاهی غیر قابل کنترل بود. به این کد به اصطلاح callback hell میگویند. برای آشنایی بیشتر با این کدها و درک بهتر آن توصیه میکنیم مقالهی callback hell را مطالعه کنید.
در نتیجه برای جلوگیری از وقوع این مسئله Promise معرفی شد.
Promise به ما کمک میکند، کدهای خوانا و تمیزتری بنویسیم، که قابلیت خطایابی و مدیریت کردن بالاتری نسبت به callback functionها دارد. به طور کلی مزایای Promise عبارتند از:
1- Promise قابلیت خواندن کد را افزایش میدهد.
2- با Promise عملیات asynchronous را بهتر میشود مدیریت کرد.
3- در Promise میتوانیم خطاهارا بهتر مدریت کنیم.
پیشتر گفتیم Promise در جاوا اسکریپت مانند قول و قرار هایی که در زندگی واقعی میگذاریم، کار میکند. یعنی همانطور که ما قولی را برای انجام کاری در آینده به کسی میدهیم، و احتمال دارد، به آن قول پایبند باشیم، یا رد کنیم، در جاوا اسکریپت هم هنگامی که ما یک Promise را تعریف میکنیم، با فرا رسیدن زمان آن یا آن Promise حل میشود، یا به هر دلیلی رد میشود.
برای مثال فرض کنیم درخواستی را به سمت وب ارسال کردهایم و منتظر در یافت پاسخ هستیم. حال دو حالت وجود دارد، یا به آن درخواست پاسخ داده میشود، و نتیجهی در خواست را میبینیم، یا به هر دلیلی در خواست رد میشود، و در نتیجه Error ارسالی از سمت وب را مشاهده میکنیم.
به شکل زیر دقت کنید:
همانطور که در شکل بالا میبینید، برای مثال زمانی که ما یک در خواست را توسط Promise به سمت وب ارسال میکنیم، تا زمانی که داده هایمان را دریافت نکنیم، در حالت (PENDING) یا انتظار قرار داریم. در صورتی که ما اطلاعات را از server در یافت کنیم، Promise با موفقیت به انجام میرسد، و حالت (RESOLVED) اتفاق میافتد، در غیر این صورت حالت (REJECTED) اتفاق میافتد.
یک Promise به طور کلی در سه وضعیت زیر قرار دارد:
pending: به حالتی گفته میشود، که در آن Promise هنوز پاسخ داده نشده و وضعیت آن مشخص نیست.
fulfilled: به حالتی گفته میشود، که اقدامات مربوط به Promise موفقیت آمیز باشد.
rejected: به حالتی گفته میشود، که Promise موفق آمیز نباشد.
لازم به ذکر است که میتوانیم Promise زنجیرهای داشته باشیم. بدین ترتیب میتوانیم، کاری کنیم، که یک سری عملیات زنجیرهای غیر همزمان با هم اجرا شوند. در چنین حالتی اجرای عملیات جدید منوط به اجرای موفقیت آمیز عملیات قبل است.
یک Promise میتواند با استفاده از constructor مانند زیر ایجاد شود:
var promise = new Promise(function(resolve, reject){ //do something });
در قطعه کد فوق یک متغیر به نام promise ایجاد کردهایم، و با کلید واژه new سازنده یا (constructor)، را صدا زدهایم، و در ادامه یک callback function را به عنوان پارامتر به سازنده دادهایم، که این callback function خود دو تابع با نامهای resolve و reject دریافت میکند.
در ادامه عملیات داخل این callback function انجام میشود، حال اگر عملیات موفقیت آمیز بود، تابع resolve و در غیر این صورت تابع reject فراخوانی میشود. به مثال زیر توجه کنید:
var promise = new Promise(function(resolve, reject){
var str="7learn.com";
var site="7learn.com";
if(str===site) {
resolve();
} else {
reject();
}
});
در مثال بالا برابری دو رشته را با هم برای موفقیت آمیز بودن یا نبودن به صورت شرط قرار دادهایم. حال سوالی پیش میآید، اگر شرط برقرار بود و تابع resolve شد عملیاتی که در ادامه قرار است انجام شود را چگونه پیاده سازی کنیم؟ یا اگر شرط برقرار نبود و تابع reject فراخوانی شد یا حتی خطایی ارسال شد این وضعیت چگونه مدیریت میشود؟
برای این کار از دو تابع به نامهای then و catch استفاده میکنیم.در ابتدا به معرفی و بررسی تابع then میپردازیم :
.then(function(result){
//handle success
}, function(error){
//handle error
})
تابع then دو تابع دیگر به عنوان پارامتر دریافت میکند. که اگر نتیجهی Promise موفقیت آمیز بود، کد هایی که در تابع اول وجود دارد، اجرا میشود، در غیر این صورت کد هایی که درون تابع دوم وجود دارد، اجرا میشود. لازم به ذکر است که وجود تابع دوم ضروری نیست، و به عبارت بهتر Optional میباشد، و بهتر است برای مدیریت کردن خطاها از catch استفاده کنیم.
نحوهی استفاده از catch به صورت زیر است:
.catch(function(error){
//handle error
})
حال به مثال قبل باز میگردیم و برای استفاده از Promise به صورت زیر عمل میکنیم:
promise.then(function () {
console.log('Promise is successfully.');
}).
catch(function () {
console.log('Some error has occured');
});
حال اگر Promise، موفق باشد در کنسول عبارت Promise is successfully، و در غیر این صورت در کنسول، عبارت Some error has occurred نمایش داده میشود.
جمعبندی:
در این مقاله سعی شد تا مفاهیم سادهای از Promise برای آشنایی مقدماتی با آن ارائه شود. به طور کلی در Promise زمانی که درخواستی ارسال میشود یا کاری انجام میشود Promise در ابتدا قبل از دریافت پاسخ در حالت انتظار یا PENDING قرار دارد. حال با دو حالت روبه رو هستیم اگر Promise موفقیت آمیز بود کدهایی که در تابع then تعریف کرده بودیم اجرا میشود در غیر این صورت کد هایی که در تابع catch تعریف کردهایم اجرا میشود. Promise به دلیل ساختاری که دارد، برای مدیریت کردن خطاها و زدن کد تمیز کمک زیادی به ما میکند.
اگر به یادگیری بیشتر در زمینه جاوا اسکریپت علاقه داری، با شرکت در دوره آموزشی متخصص جاوا اسکریپت در کمتر از یک سال به یک متخصص JS همه فن حریف تبدیل میشوی که آمادهی استخدام، دریافت پروژه و یا فول-استک شدن هستی.