Promise به معنای قول دادن و پيمان بستن است. فرض كنيد به يكی از دوستانتان قول دادهايد كه آخر هفته با او به يكی از كافههای سطح شهر برويد. حال دو حالت وجود دارد. از آنجايی كه قرار است آخر هفته كه يك زمان در آينده است، اين كار انجام شود، احتمال دارد بتوانيد به قول خود پايبند باشيد، و احتمال دارد كاری برای شما پيش بيايد و نتوانيد به قول خود عمل كنيد. مفهوم promise در جاوا اسکریپت ، رفتاری مشابه به اين بحث دارد، كه در ادامه به آن میپردازيم.
promise در جاوا اسکریپت چیست
قبل از پرداختن به هر موضوعی میخواهيم به پاسخ اين سوال بپردازيم، كه كاربرد Promise چيست؟
در جاوا اسكريپت Promise كاربردی مشابه callback function دارد. به این معنی که از Promise همانند callback function برای مدیریت کردن دستورات غیر همزمان یا asynchronous استفاده میکنیم. حال سوال پیش میآید که منظور از دستورات asynchronous چیست؟
پردازش کد در کامپیوترزبان جاوا اسکریپت یک زبان مفسری است. در زبانهای مفسری، اجرای کدها به صورت خط به خط است. همچنین جاوا اسکریپت یک زبان رویدادگرا نیز هست. به این معنی که زمانیکه در ترجمه خط به خط کدها مفسر به یک بخشی از کد برای مثال به یک تابع برخورد میکند که فرآیند دریافت پاسخ توسط تابع طولانی است، همزمان با اجرای آن بخش از کد، به خطهای بعدی برنامه رفته و آنها را اجرا میکند. زمانی که پاسخ از تابع زمانبر دریافت شد، برای اجرا باید منتظر اتمام اجرای کدهای جلوتر خود باشد. به نوعی وارد یک صف اجرا میشود که برای اجرا باید منتظر شود که به اول این صف برسد و سپس اجرا شود. به دو صورت زیر انجام میشود:
- 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 دو تابع دیگر به عنوان پارامتر دریافت میکند. که اگر نتیجهی 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 همه فن حریف تبدیل میشوی که آمادهی استخدام، دریافت پروژه و یا فول-استک شدن هستی.
۴۳ دیدگاه
هادی آقاجانی۰۳ اسفند ۱۴۰۲، ۱۱:۲۹
سلام . خیلی خوب و واضح توضیح داده شده است و یکی از بهترین متنهایی که برای Promise بود رو اینجا دیدم .
فقط وقتی آسنکرون میشود چگونه استفاده میشود را هم خوبه به متن اضافه کنید . با تشکر
نازنین کریمی مقدم۰۷ اسفند ۱۴۰۲، ۰۶:۲۷
درود
ممنون که با ما همراه هستید. برای سوالتون پیشنهاد میکنم به این لینک مراجعه کنید خیلی جامع و قشنگ توضیح داده:
https://www.freecodecamp.org/news/how-to-use-promises-in-javascript/#:~:text=The%20async%20keyword%20is%20used,in%20a%20more%20synchronous%20manner.
جواد رفیعی۱۹ اسفند ۱۴۰۱، ۰۷:۵۵
ممنون از شما.
۱۶ آذر ۱۴۰۱، ۱۷:۲۷
ممنون بابت توضیحاتتون خیلی کمک کنندهاس.
فقط لینکی که برای معرفی callback hell گذاشتید مشکل داره.
همچین نشانیایه: https://callbackhell.com/
ضعیفترین مقالعه ای بود که دیدم و اشتباهات زیادی داشت ( اسم خودتون رو برنامه نویس نزارین )
۳۰ بهمن ۱۴۰۰، ۲۰:۳۶
سلام و درود
انصافا خیلی ساده و روان توضیح داده بود و باعث مطلب رو درک کنیم
Hamidreza Akbarnezhad۲۳ دی ۱۴۰۰، ۱۱:۲۶
ممنون از مقاله خوبتون. من هنوز اول مقاله هستم. ولی این جمله در ابتدای مقاله دوبار تکرار شده که اصلا جالب نبود برام:
"زبان جاوا اسکریپت یک زبان مفسری است. در زبانهای مفسری، اجرای کدها به صورت خط به خط است. همچنین جاوا اسکریپت یک زبان رویدادگرا نیز هست. به این معنی که زمانی که، در ترجمه خط به خط کدها مفسر به یک بخشی از کد برای مثال به یک تابع برخورد میکند. که فرآیند دریافت پاسخ توسط تابع طولانی است، همزمان با اجرای آن بخش از کد، به خطهای بعدی برنامه رفته و آنها را اجرا میکند."
لطفا اصلاح بشه. باتشکر
۱۰ دی ۱۴۰۰، ۰۰:۱۷
خیلی ممنون از مقاله خوبتون
در قسمت هایی که به مقاله callback function چیست لینک دادین؛ لینکها کار نمیکنه
یعنی قسمت tutorials در لینک باید به blog تبدیل بشه
بازم ممنون از مقاله خوبتون
نازنین کریمی مقدم۱۱ دی ۱۴۰۰، ۱۰:۳۰
درود
بله حق با شماست اون لینک رو حذف کردیم، اما پایین همون پاراگراف یه لینک دیگه گذاشتیم که اون اوکیه خداروشکر
ایشالا سرمون خلوت بشه یه بررسی جامع رو موارد این چنینی خواهیم داشت. ممنون که با ما همراه هستید.
۱۹ آذر ۱۴۰۰، ۰۹:۵۴
واقعا عالی ، خیلی عالی توضیح دادین من ازپنج دوره مختلف اقسمتی هایی که در مورد promise گفته شده بود رو نگاه کردم اما متوجه نشدم، اما بعد از این مقالعه کلا این موضوع برام جا افتاد
نازنین کریمی مقدم۱۹ آذر ۱۴۰۰، ۱۵:۳۹
خوشحالیم مقاله براتون مفید بوده دوست عزیز :)
محمد۳۰ آبان ۱۴۰۰، ۲۱:۰۷
عالی بود مرسی ????
مهدی ۱۲ مهر ۱۴۰۰، ۰۹:۱۸
عالی خوب توضیح دادین
نازنین کریمی مقدم۱۲ مهر ۱۴۰۰، ۱۱:۱۹
ممنون که با ما همراه هستید.
zahra ghorbani۱۱ شهریور ۱۴۰۰، ۰۷:۳۰
kheili awli bod mamnoon .
khaste nabashid
نازنین کریمی مقدم۱۳ شهریور ۱۴۰۰، ۱۲:۵۱
درود
ممنون که با ما همراه هستید
zahra ghorbani۱۱ شهریور ۱۴۰۰، ۰۷:۲۹
خیلی عالیییی بود ممنون .
نازنین کریمی مقدم۱۳ شهریور ۱۴۰۰، ۱۲:۴۶
ممنون که با ما همراه هستید.
عاطفه۲۸ اردیبهشت ۱۴۰۰، ۱۸:۴۲
خیلی عالی بود دستتون درد نکنه. چه خوب توضیح دادید.
faezeh۱۹ بهمن ۱۳۹۹، ۱۱:۵۸
خیلی مفید و کاربردی بود ممنون
محمد جواد۰۲ دی ۱۳۹۹، ۱۳:۲۱
بسیار عالی انشاالله روزی برسه دیگه نریم mdn بجاش بیام 7learn
کار نشد نداره
:)
ehsan۲۱ آبان ۱۳۹۹، ۰۸:۱۵
مگه داریم توضیح ازین قشنگتر.
من برنامه نویسیو با سون لرن شروع کردم.واقعا قوی هستین.ایولاااااااااااااااااااااا
Mohammad۲۶ مهر ۱۳۹۹، ۱۴:۰۰
سلام خدمت شما
ممنون از این مقاله مفید
فکر کنم اگه یه مقدار بیشتر مثال توی مقاله باشه بهتر بشه مفهوم رو جا انداخت
یا مثلا در آخر سر کد هایی که توی مقاله آوردین رو سر هم کنین:
نازنین کریمی مقدم۲۶ مهر ۱۳۹۹، ۲۳:۴۱
سلام.
ممنون از فیدبکتون سعی میکنیم در مقالات بعدی به این نکته دقت کنیم :)
محمود نقی خانی۲۵ مهر ۱۳۹۹، ۰۳:۵۳
درود بر شما
به عنوان یک آماتور (خیلی آماتور)، در تفسیر متون انگلیسی درمانده شده بودم. با خود میگفتم:"امکان ندارد مباحث پیشرفته PWA در ایران مستند شد باشد. افسوس که ما ایرانیها خیلی از قافله عقبیم." که به صورت تفاقی این مقاله را دیدم.
آفرین بر شما گرامیان.
آدم مذهبی اصلا نیستم ولی
"اگر علم در ثریا باشد، ایرانیان بر آن دست خواهند یافت."
لذت بردم و بسیار
سپاس گزارم
ارادتمند شما
محمود نقی خانی
نازنین کریمی مقدم۲۷ مهر ۱۳۹۹، ۰۰:۱۳
سلام. ممنون بابت همراهی و انرژی مثبتی که به ما میدید :)
elmira۱۲ مهر ۱۳۹۹، ۱۷:۵۷
سلام.
من مفهوم وجود functionهای موجود در متدهایی مثل setTimeout(function(){
و یا then(function(){}
رو در نمیکنم، چرا وقتی setTimeout که خودش یک متد هست باید داخلش function نوشته بشه!؟ و اصولاً این نوع functionهای بدون نام چکاره اند؟
نازنین کریمی مقدم۱۲ مهر ۱۳۹۹، ۱۹:۱۷
سلام.
همونطور که در متن گفتیم، تابع then دو تابع دیگر به عنوان پارامتر دریافت میکند : تابع موفقیت و تابع شکست. که اگر نتیجهی Promise موفقیت آمیز بود، کد هایی که در تابع موفقیت وجود دارد، اجرا میشود، در غیر این صورت کد هایی که درون تابع شکست وجود دارد، اجرا میشود.
در حقیقت اون توابع دومی که داریم اون داخل مینویسم، توابعی هستند که بعد از تابع اصلی اجرا میشوند. تابع then و setTimeout مثل یک پل هستند. تضمین میکنند که تابع اول کامل انجام بشه و بعد تابع دوم شروع به کار کنه.
اگر متوجه نشدید حتما بگید که با یک مثال براتون قضیه رو باز کنم.
احمد۰۱ مهر ۱۳۹۹، ۲۲:۵۶
سلام عرض میکنم. اصلا عادت ندارم نظر بدم توی هیچ سایتی، ولی واقعا جا داره یه تشکر ویژه یکنم از نویسنده این مقاله که انقدر تمیز و زیبا توضیح داده بود این مبحث رو. ممنونم واقعا
نازنین کریمی مقدم۰۲ مهر ۱۳۹۹، ۰۷:۵۳
سلام. خوشحالیم که مقاله براتون مفید بوده.
Mehdi۱۷ شهریور ۱۳۹۹، ۱۱:۲۷
سلام
بسیار عالی توضیح دادید و لطفا چند مثال دیگه هم بزارید. پس اعمال عملیات ناهمگام به این هدف انجام میشود که بتوان وابستگیهای یک عملیات را قبل از به پیان رسیدن یه متد مدیریت کرد. که این وابستگی با توجع به نو در عملکرد دارای زمان متغیری است . درسته ؟
نازنین کریمی مقدم۰۲ مهر ۱۳۹۹، ۰۸:۳۳
سلام.
دقیقا همینطوره و نمیشه زمان دقیقی براش تعریف کرد.
فرض کنید در سمت سرور میخوایم که مقادیری رو آپدیت کنیم و بعد اون مقادیر جدید رو در جدولی در برنامه نمایش بدیم. اینجا باید حواسمون باشه که اول تابع آپدیت کامل کارش رو انجام بده و بعد تابع گت اطلاعات صدا زده بشه. حالا اینکه چقدر آپدیت طول بکشه مشخص نیست، اما با استفاده از promise ما تضمین میکنیم که تابع گت بعد از آپدیت انجام بشه تا بتونیم مقادیر رو درست نمایش بدیم.
مجتبی۰۹ شهریور ۱۳۹۹، ۰۷:۳۲
واقعا حرف نداشت بسیار ساده و قابل فهم بود.
فائقه نامور۱۱ شهریور ۱۳۹۹، ۱۵:۳۹
سلام وقت بخیر
ممنون از توجه شما دوست عزیز
بابک راد۰۱ مرداد ۱۳۹۹، ۱۹:۴۰
شما نوشتید:
در جاوا اسکریپت کد به صورت ناهمگام پردازش میشود و مفسر منتظر پاسخ سرور نمیماند و ادامهی برنامه را اجرا میکند و این اتفاقی است، که نمیخواهیم بیافتد.
چرا نمیخواهید این اتفاق بیفتد؟؟ در حالی که جملات بالا دقیقا تعریف ناهمزمانی کد هست. در معنای دقیقتر کد جاوااسکریپت نباید منتظر پاسخ بخشی دیگری از کد بمونه و باید روند تفسیر کد تا انتها رو ادامه بده.
فاطمه افشار۰۲ مرداد ۱۳۹۹، ۰۴:۱۴
سلام همراه عزیز
ممنونم از بیان این نکته ?
مفهوم خوب بیان نشده بود
اصلاح شد
Mohammad۲۵ تیر ۱۳۹۹، ۰۷:۴۱
بسیار روان و ساده بیان شد. ممنون از شما. من چندین بار این مفهوم رو خونده بودم ولی بازم درست درک نمیکردم.
فاطمه افشار۲۶ تیر ۱۳۹۹، ۰۸:۲۹
خواهش میکنم ?
همه ی تلاش ما این هست که مفاهیم رو به زبان ساده و قابل فهم بیان کنیم
خوشحالیم که اینطور بوده?