توی این مطلب قصد داریم به promise ها از یک زاویه دیگه نگاه کنیم. اول از همه بگم که این مطلب برای افرادی نوشته شده که دانش خوبی از زبان javascript دارن و علاقه دارن مبحث promise ها رو عمیق تر یاد بگیرن.
یک promise بعد از initial شدن در وضعیت pending قرار میگیره، اگه promise با مقدار x resolve بشه و ضعیت promise به fulfilled تغییر کرده و x، مقدار fulfillment اون promise میشه و اگه promise با مقدار e reject بشه وضعیت promise به rejected تغییر میکنه و e مقدار rejection اون promise میشه (resolve یا reject شدن یک promise تنها یکبار انجام میشه).
به شکل زیر نگاه کنین:
با اجرای این کد بعد از گذشت ۳ ثانیه promise resolve شده و مقدار fulfillment value is :1 در خروجی چاپ میشه
این تابع دو callback function میگیره (onFulfilled,onRejected)، اگه promise resolve بشه تابع onFulfilled با مقداری که promise با اون resolve شده فراخوانی میشه، یا درصورت reject شدن promise، تابع onRejected با مقداری که promise با اون reject شده فراخوانی میشه.
برای اینکه دقیق تر متوجه عملکرد این تابع بشیم،قطعه کد زیر رو ببینید(در واقعیت پیاده سازی تابع به این شکل نیست اما بر اساس همین منطق عمل میکنه):
در ابتدا دو task برای حالت fulfillment و rejection ساخته شده که عملکرد اونها واضحه(درصورت resolve یا reject شدنه promise، هر کدوم callback function مربوط به همون وضعیت رو با مقداری که promise با اون resolve یا reject شده فراخوانی میکنند)سپس وضعیت فعلی promise بررسی میشه که حالت های زیر ممکنه اتفاق بیوفته:
تابع catch در واقع همون تابع then هست که onRejected callback function رو نداره.
دو فراخوانی زیر معادل هم هستن:
تا اینجا فقط از resolve یا reject کردن promise اسم بردیم.برای فهمیدن منطق عملکرد اونا قطعه کد زیر رو ببینین (در واقعیت پیاده سازی تابع به این شکل نیست اما بر اساس همین منطق عمل میکنه):
چون promise تنها یکبار میتونه resolve یا reject بشه، پس ابتدا این بررسی انجام میشه.اگه promise در وضعیتی جز pending باشه، خود promise برگشت داده میشه( که مجدد بتونیم روی اون then بزنیم). در غیر این صورت وضعیت promise به fulfilled تغییر میکنه، سپس مقداری که promise با آن resolve شده در محلی ذخیره میشه و در نهایت تمام task های fulfillmentو rejection که ذخیره شده، پاک میشه و task های fulfillment داخل microtasks queue منتقل میشه.
تابع reject هم از همین منطق پیروی میکنه.
با اجرای این کد بعد از گذشت ۳ ثانیه مقادیر fulfillment value is: 1 و fulfillment value is: 2 به ترتیب در خروجی چاپ میشه.اما تابع then چطور این حالت (زنجیره شدن) رو هندل میکنه؟
تابع then(همینطور catch) خودش یک promise برمیگردونه. به قطعه کد زیر دقت کنین(در واقعیت پیاده سازی تابع به این شکل نیست اما بر اساس همین منطق عمل میکنه)
با اجرای این کد بعد از گذشت ۳ ثانیه مقدار fulfillment value is: 1 و بعد از ۳ ثانیه دیگر ( جمعا ۶ ثانیه) مقدار another fulfillment value is: 2 در خروجی چاپ میشه.
گفتیم که تابع then (همینطور catch) خودش یک promise جدید برمیگردونه؛ پس کد مثال ۳ باید به صورت زیر باشه:
یعنی promise ای که ما return کردیم، باید wrap بشه درونه promise ای که خوده then (یا catch) return میکنه. اما در واقعیت کد مثال ۳ (عکس قبل از عکس بالا) درسته. پس داستان چیه??
اگه بخوام مختصر و مفید راجبش بگم، یه چیزی داریم به اسم thenable (هر چیزی که then داشته باشه ؛ مثل خود promise که تابع then داره). زمانی که شما یک thenable (لزوما promise نیست و میتونه یه object باشه که تابع then داره) از تابع then (یا catch) return میکنین،دیگه داخل promise ای که then (یا catch) return میکنه، wrap نمیشه بلکه promise قفل میشه روی thenable که اگه resolve یا reject بشه، promise هم resolve یا reject میشه. شکل زیر حالت promise برگشت داده شده از تابع then (یا catch) رو نشون میده:
اگه علاقه مند بودین بیشتر راجب این مبحث بدونین لینک زیر کامل مطالب رو گفته:
Flattening Promises in the ECMAScript specification
در آخر هم باید بگم ممنون که زمان گذاشتین و این مطلب رو خوندین و خوشحال میشم اگه نظری داشتین برام comment کنین??