Promise به معنای قول دادن و پيمان بستن است. فرض كنيد به يكی از دوستانتان قول دادهايد كه آخر هفته با او به يكی از كافههای سطح شهر برويد. حال دو حالت وجود دارد. از آنجايی كه قرار است آخر هفته كه يك زمان در آينده است، اين كار انجام شود، احتمال دارد بتوانيد به قول خود پايبند باشيد، و احتمال دارد كاری برای شما پيش بيايد و نتوانيد به قول خود عمل كنيد. مفهوم promise در جاوا اسکریپت ، رفتاری مشابه به اين بحث دارد، كه در ادامه به آن میپردازيم.
فهرست محتوای این مقاله
promise در جاوا اسکریپت چیست
قبل از پرداختن به هر موضوعی میخواهيم به پاسخ اين سوال بپردازيم، كه كاربرد Promise چيست؟
در جاوا اسكريپت Promise كاربردی مشابه callback function دارد. به این معنی که از Promise همانند callback function برای مدیریت کردن دستورات غیر همزمان یا asynchronous استفاده میکنیم. حال سوال پیش میآید که منظور از دستورات asynchronous چیست؟ برای درک بهتر این مورد بخشی از مقالهی callback function چیست را در اینجا ذکر میکنیم.
پردازش کد در کامپیوترزبان جاوا اسکریپت یک زبان مفسری است. در زبانهای مفسری، اجرای کدها به صورت خط به خط است. همچنین جاوا اسکریپت یک زبان رویدادگرا نیز هست. به این معنی که زمانیکه در ترجمه خط به خط کدها مفسر به یک بخشی از کد برای مثال به یک تابع برخورد میکند که فرآیند دریافت پاسخ توسط تابع طولانی است، همزمان با اجرای آن بخش از کد، به خطهای بعدی برنامه رفته و آنها را اجرا میکند. زمانی که پاسخ از تابع زمانبر دریافت شد، برای اجرا باید منتظر اتمام اجرای کدهای جلوتر خود باشد. به نوعی وارد یک صف اجرا میشود که برای اجرا باید منتظر شود که به اول این صف برسد و سپس اجرا شود. به دو صورت زیر انجام میشود:
- Asynchronous یا پردازش ناهمگام (غیر همزمان): در این نوع پردازش، زمانی که پردازشگر شروع به پردازش میکند، بدون اینکه منتظر اتمام پردازش اول باشد، پردازش دوم را شروع میکند.
- synchronous یا پردازش همگام (Blocking): در این نوع پردازش، پردازشگر ابتدا پردازش اول را به طور کامل به پایان میرساند، سپس پردازش دوم را شروع میکند.
زبان جاوا اسکریپت یک زبان مفسری است. در زبانهای مفسری، اجرای کدها به صورت خط به خط است. همچنین جاوا اسکریپت یک زبان رویدادگرا نیز هست. به این معنی که زمانی که، در ترجمه خط به خط کدها مفسر به یک بخشی از کد برای مثال به یک تابع برخورد میکند. که فرآیند دریافت پاسخ توسط تابع طولانی است، همزمان با اجرای آن بخش از کد، به خطهای بعدی برنامه رفته و آنها را اجرا میکند. شرایطی را در نظر بگیرید، که در خواستی را به یک سرور ارسال کردهاید، تا اطلاعاتی را دریافت کنید، که در ادامه به آن اطلاعات احتیاج دارید، تا توابعی که تعریف کردهاید، از آن اطلاعات استفاده کنند. فرض کنید ارسال پاسخ از سمت سرور کمی طولانی شده است. میخواهیم کاری کنیم تازمانی که پاسخ سرور مشخص نشده است، کدهای بعدی اجرا نشود. راه حل چیست؟ راه حل این است، که یا از Promise یا از callback function استفاده کنیم.
توصیه میکنیم قبل از خواندن ادامهی مقاله، برای درک بهتر و آشنایی با callback function، مقالهی callback function چیست را مطالعه کنید.
Callback Function یا Promise
پیشتر گفتیم کاربرد Promise همانند callback function است. حال کدام یک از این دو انتخاب بهتری است؟
قبل از اینکه Promise معرفی شود برای انجام چند وظیفهی غیر هم زمان از callback function استفادهی زیادی میشد. استفاده از callback functionها مشکلاتی نیز به همراه داشت، که یکی از این مشکلات این بود که در برخی موارد منجر به تولید کدی میشد، که مدیریت کردن و خطایابی آن بسیار مشکل بود و گاهی غیر قابل کنترل بود. به این کد به اصطلاح callback hell میگویند. برای آشنایی بیشتر با این کدها و درک بهتر آن توصیه میکنیم مقالهی callback hell را مطالعه کنید.
در نتیجه برای جلوگیری از وقوع این مسئله Promise معرفی شد.
مزایای promise در جاوا اسکریپت
Promise به ما کمک میکند، کدهای خوانا و تمیزتری بنویسیم، که قابلیت خطایابی و مدیریت کردن بالاتری نسبت به callback functionها دارد. به طور کلی مزایای Promise عبارتند از:
1- Promise قابلیت خواندن کد را افزایش میدهد.
2- با Promise عملیات asynchronous را بهتر میشود مدیریت کرد.
3- در Promise میتوانیم خطاهارا بهتر مدریت کنیم.
promise در جاوا اسکریپت چگونه کار میکند؟
پیشتر گفتیم Promise در جاوا اسکریپت مانند قول و قرار هایی که در زندگی واقعی میگذاریم، کار میکند. یعنی همانطور که ما قولی را برای انجام کاری در آینده به کسی میدهیم، و احتمال دارد، به آن قول پایبند باشیم، یا رد کنیم، در جاوا اسکریپت هم هنگامی که ما یک Promise را تعریف میکنیم، با فرا رسیدن زمان آن یا آن Promise حل میشود، یا به هر دلیلی رد میشود.
برای مثال فرض کنیم درخواستی را به سمت وب ارسال کردهایم و منتظر در یافت پاسخ هستیم. حال دو حالت وجود دارد، یا به آن درخواست پاسخ داده میشود، و نتیجهی در خواست را میبینیم، یا به هر دلیلی در خواست رد میشود، و در نتیجه Error ارسالی از سمت وب را مشاهده میکنیم.
به شکل زیر دقت کنید:
همانطور که در شکل بالا میبینید، برای مثال زمانی که ما یک در خواست را توسط Promise به سمت وب ارسال میکنیم، تا زمانی که داده هایمان را دریافت نکنیم، در حالت (PENDING) یا انتظار قرار داریم. در صورتی که ما اطلاعات را از server در یافت کنیم، Promise با موفقیت به انجام میرسد، و حالت (RESOLVED) اتفاق میافتد، در غیر این صورت حالت (REJECTED) اتفاق میافتد.
یک Promise به طور کلی در سه وضعیت زیر قرار دارد:
pending: به حالتی گفته میشود، که در آن Promise هنوز پاسخ داده نشده و وضعیت آن مشخص نیست.
fulfilled: به حالتی گفته میشود، که اقدامات مربوط به Promise موفقیت آمیز باشد.
rejected: به حالتی گفته میشود، که Promise موفق آمیز نباشد.
لازم به ذکر است که میتوانیم 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 همه فن حریف تبدیل میشوی که آمادهی استخدام، دریافت پروژه و یا فول-استک شدن هستی.
خیلی مفید و کاربردی بود ممنون
بسیار عالی انشاالله روزی برسه دیگه نریم mdn بجاش بیام 7learn
کار نشد نداره
🙂
مگه داریم توضیح ازین قشنگتر.
من برنامه نویسیو با سون لرن شروع کردم.واقعا قوی هستین.ایولاااااااااااااااااااااا
سلام خدمت شما
ممنون از این مقاله مفید
فکر کنم اگه یه مقدار بیشتر مثال توی مقاله باشه بهتر بشه مفهوم رو جا انداخت
یا مثلا در آخر سر کد هایی که توی مقاله آوردین رو سر هم کنین:
سلام.
ممنون از فیدبکتون سعی میکنیم در مقالات بعدی به این نکته دقت کنیم 🙂
درود بر شما
به عنوان یک آماتور (خیلی آماتور)، در تفسیر متون انگلیسی درمانده شده بودم. با خود می گفتم:”امکان ندارد مباحث پیشرفته PWA در ایران مستند شد باشد. افسوس که ما ایرانی ها خیلی از قافله عقبیم.” که به صورت تفاقی این مقاله را دیدم.
آفرین بر شما گرامیان.
آدم مذهبی اصلا نیستم ولی
“اگر علم در ثریا باشد، ایرانیان بر آن دست خواهند یافت.”
لذت بردم و بسیار
سپاس گزارم
ارادتمند شما
محمود نقی خانی
سلام. ممنون بابت همراهی و انرژی مثبتی که به ما میدید 🙂
سلام.
من مفهوم وجود function های موجود در متدهایی مثل setTimeout(function(){
و یا then(function(){}
رو در نمیکنم، چرا وقتی setTimeout که خودش یک متد هست باید داخلش function نوشته بشه!؟ و اصولاً این نوع function های بدون نام چکاره اند؟
سلام.
همونطور که در متن گفتیم، تابع then دو تابع دیگر به عنوان پارامتر دریافت میکند : تابع موفقیت و تابع شکست. که اگر نتیجهی Promise موفقیت آمیز بود، کد هایی که در تابع موفقیت وجود دارد، اجرا میشود، در غیر این صورت کد هایی که درون تابع شکست وجود دارد، اجرا میشود.
در حقیقت اون توابع دومی که داریم اون داخل مینویسم، توابعی هستند که بعد از تابع اصلی اجرا میشوند. تابع then و setTimeout مثل یک پل هستند. تضمین میکنند که تابع اول کامل انجام بشه و بعد تابع دوم شروع به کار کنه.
اگر متوجه نشدید حتما بگید که با یک مثال براتون قضیه رو باز کنم.
سلام عرض میکنم. اصلا عادت ندارم نظر بدم توی هیچ سایتی، ولی واقعا جا داره یه تشکر ویژه یکنم از نویسنده این مقاله که انقدر تمیز و زیبا توضیح داده بود این مبحث رو. ممنونم واقعا
سلام. خوشحالیم که مقاله براتون مفید بوده.
سلام
بسیار عالی توضیح دادید و لطفا چند مثال دیگه هم بزارید. پس اعمال عملیات ناهمگام به این هدف انجام میشود که بتوان وابستگی های یک عملیات را قبل از به پیان رسیدن یه متد مدیریت کرد. که این وابستگی با توجع به نو در عملکرد دارای زمان متغیری است . درسته ؟
سلام.
دقیقا همینطوره و نمیشه زمان دقیقی براش تعریف کرد.
فرض کنید در سمت سرور میخوایم که مقادیری رو آپدیت کنیم و بعد اون مقادیر جدید رو در جدولی در برنامه نمایش بدیم. اینجا باید حواسمون باشه که اول تابع آپدیت کامل کارش رو انجام بده و بعد تابع گت اطلاعات صدا زده بشه. حالا اینکه چقدر آپدیت طول بکشه مشخص نیست، اما با استفاده از promise ما تضمین میکنیم که تابع گت بعد از آپدیت انجام بشه تا بتونیم مقادیر رو درست نمایش بدیم.
واقعا حرف نداشت بسیار ساده و قابل فهم بود.
سلام وقت بخیر
ممنون از توجه شما دوست عزیز
شما نوشتید:
در جاوا اسکریپت کد به صورت ناهمگام پردازش میشود و مفسر منتظر پاسخ سرور نمیماند و ادامهی برنامه را اجرا میکند و این اتفاقی است، که نمیخواهیم بیافتد.
چرا نمیخواهید این اتفاق بیفتد؟؟ در حالی که جملات بالا دقیقا تعریف ناهمزمانی کد هست. در معنای دقیقتر کد جاوااسکریپت نباید منتظر پاسخ بخشی دیگری از کد بمونه و باید روند تفسیر کد تا انتها رو ادامه بده.
سلام همراه عزیز
ممنونم از بیان این نکته 🌺
مفهوم خوب بیان نشده بود
اصلاح شد
بسیار روان و ساده بیان شد. ممنون از شما. من چندین بار این مفهوم رو خونده بودم ولی بازم درست درک نمیکردم.
خواهش میکنم 😊
همه ی تلاش ما این هست که مفاهیم رو به زبان ساده و قابل فهم بیان کنیم
خوشحالیم که اینطور بوده😊