جاوا اسکریپت به عنوان یه زبون از نوع single thread در هر لحظه، حداکثر یک کار انجام میده. ولی این به اون معنا نیست که ما باید منتظر بمونیم تا یه کار سنگین تموم شه تا بعدش یه کار سبک رو به جاوا اسکریپت بسپاریم. مگه نه؟
ما لنگ نمیمونیم چون Web API ها و مرورگر دوست داشتنی خودمون رو داریم. توابعی مثل setTimeout، setInterval، fetch اجازه میدن تا فعالیت هایی که زمان زیادی نیاز دارن توی پشت پرده ی جاوا اسکریپت انجام بشن و تا اون لحظه سایر کارهامون هم رها نشن. تازه Web API ها به همین 3 تا دونه خاتمه پیدا نمیکنن و خیلی بیشتر از این حرفان.
هر کدوم از ماموریت هایی که ما برای JS در نظر میگیریم از بالا تا پایین، یکی یکی میرن توی Call Stack و اونجا میمونن تا نوبتشون بشه و اجرا بشن.
توی این مثال، اول از همه، خط اول میره توی call stack و one توی کنسول مرورگر پرینت میشه. بعدش نوبت two هستش. بعد از اون تابع logThreeAndFour فراخونی میشه. این تابع داخل خودش تابع logThree رو صدا میزنه و در ادامه همین تابع عبارت Three رو توی کنسول به نمایش میذاره. در آخر به تابع logThreeAndFour برمیگردیم تا Four هم توی کنسول پرینت شه.
تو این یکی اول تابع longRunningTask میره توی call stack و حالا باید تا موهامون مثل دندونمون سفید شه منتظر به پایان رسیدن اون چرخه for باشیم. هر وقت تموم شد نوبت به نمایش Long task done در مرورگر میرسه. بعد از اون importantTask فراخونی میشه تا Important توی کنسول مرورگر دیده شه.
و اما اینجا ما دوتا Web API داریم به اسم setTimeout که اولیش در قدم اول اجرا میشه و از اونجایی که به 2 ثانیه زمان احتیاج داره توی call stack نمیره. پیش مرورگر منتظر میمونه تا 2 ثانیه تموم بشه. دومی هم همینطور فقط با این تفاوت که 100 میلی ثانیه برای فراخوانیش کافیه. قبل از این که اونا انجام بشن، جاوا اسکریپت میره سراغ End of script و اون رو به call stack میبره. تو قدم بعدی End of script توی کنسول پرینت میشه. 100 میلی ثانیه زمان میگذره و حالا دومین setTimeout ما آمادست تا به یه صف جدید به اسم task queue بره. این بنده خدا اونجا منتظر میمونه تا event loop بررسی کنه که آیا call stack خالی هست یا نه؟! اگر خالی بود، setTimeout ما رو میفرسته به call stack تا "100ms" توی کنسول پرینت شه. اون یکی setTimeout هم همین مسیر رو طی میکنه. اول 2 ثانیه صبر میکنه و بعد به task queue میره و بعد از اون (اگه Call stack خالی بود که اینجا هست) به Call stack و در آخرم "2000ms" روی کنسول ظاهر میشه.
یه نکته:
یه سری کارای کوچیک مثل چیزایی که داخل متد then مینویسیم تو اولویت بیشتری نسبت به task queue قرار میگیرن. این دسته از کارا صف خودشون رو دارن که بهش میگیم microtask queue و متد هایی مثل then، catch، finally و تابعی که بعد از await میان باعث تشکیل این صف میشن.
پس event loop تو این شرایط میبینه که
آیا call stack خالیه
اگر بود یه میکروتسک میفرسته به call stack
دوباره منتظر میمونه Call stack خالی شه
دوباره میره سراغ میکرو تسک
تا میکرو تسک ها تموم شن این چرخه ادامه داره
بعدش همین کارا رو با صف Task ها یا Task queue انجام میده
بگو ببینم حالا سوال اول رو میتونی خودت حل کنی؟