Promise و سه حالت آن: شناخت State پشت هر عملیات ناهمزمان
در درسهای قبل بارها با fetch و متد then کار کردهاید، اما هنوز خود شیء Promise بهطور مستقل بررسی نشده است. Promise در واقع شیئی است که نمایندهی نتیجهی نهایی یک عملیات ناهمزمان است؛ نتیجهای که ممکن است هنوز آماده نباشد، با موفقیت به پایان برسد، یا با شکست مواجه شود. این سه امکان دقیقاً همان سه State (حالت) یک Promise را تشکیل میدهند.
سه State یک Promise
هر Promise در طول عمر خود، دقیقاً یکی از این سه حالت را دارد:
| State | معنی |
|---|---|
| pending | حالت اولیه؛ عملیات هنوز در حال انجام است و نتیجهای مشخص نشده |
| fulfilled | عملیات با موفقیت به پایان رسیده و مقداری در دسترس است |
| rejected | عملیات با خطا مواجه شده است |
نکتهی مهم این است که یک Promise پس از خروج از حالت pending، دیگر هرگز به آن بازنمیگردد و حالت نهایی آن (چه fulfilled و چه rejected) قابل تغییر نیست؛ به همین دلیل گفته میشود Promise پس از settle شدن، تغییرناپذیر (immutable) است.
ساخت دستی یک Promise
Promise با استفاده از سازندهی Promise ساخته میشود که یک تابع اجراکننده (executor) میگیرد. این تابع دو پارامتر دارد: resolve برای اعلام موفقیت، و reject برای اعلام شکست:
بلافاصله پس از ساخت، Promise در حالت pending قرار دارد. تابع اجراکننده بهصورت Synchronous و بلافاصله اجرا میشود، اما فراخوانی resolve یا reject داخل آن (که در این مثال درون یک setTimeout قرار دارد) میتواند به تعویق بیفتد.
تفاوت میان resolve/reject و then/catch
یکی از سردرگمیهای رایج، خلط میان resolve/reject و then/catch است. resolve و reject توابعی هستند که سازندهی Promise را به یکی از حالتهای نهایی تغییر میدهند؛ در حالی که then و catch روشی برای واکنشنشاندادن به آن تغییر حالت از بیرون شیء Promise هستند:
| مفهوم | نقش | محل استفاده |
|---|---|---|
| resolve / reject | تغییر State داخلی Promise | داخل تابع اجراکننده (executor) |
| then / catch | واکنش به State نهایی از بیرون | روی خود شیء Promise ساختهشده |
Promise.resolve و Promise.reject
گاهی نیازی به سازندهی کامل نیست و فقط باید یک Promise با مقدار مشخص از قبل ساخته شود. برای این منظور، دو متد ایستای Promise.resolve() و Promise.reject() استفاده میشوند:
const alreadyDone = Promise.resolve("مقدار آماده");
alreadyDone.then((value) => console.log(value)); // "مقدار آماده"
const alreadyFailed = Promise.reject(new Error("خطای از پیش تعیینشده"));
alreadyFailed.catch((error) => console.log(error.message));
نکات کلیدی
- هر Promise در هر لحظه دقیقاً یکی از سه حالت pending، fulfilled یا rejected را دارد.
- پس از settle شدن (fulfilled یا rejected)، حالت یک Promise دیگر قابل تغییر نیست.
- resolve و reject حالت داخلی Promise را تغییر میدهند؛ then و catch از بیرون به آن تغییر واکنش نشان میدهند.
- Promise.resolve و Promise.reject برای ساخت سریع یک Promise با نتیجهی از پیش مشخص کاربرد دارند.
جمعبندی
شناخت سه State یک Promise—pending، fulfilled و rejected—پایهی درک دقیقتر رفتار زنجیرههای then/catch است که در درس ۲۱-۲ بررسی شد. تمایز میان resolve/reject بهعنوان ابزار تغییر حالت از درون، و then/catch بهعنوان ابزار واکنش از بیرون، یکی از مهمترین نکاتی است که درک درست آن، از بسیاری از سردرگمیهای رایج در کار با Promise جلوگیری میکند.
