همگام و ناهمگامی و راه حل های آن در جاوا اسکریپت

سلام دوستان. امیدوارم حالتون خوب باشه.همیشه یکی از چیزایی که واقعا واسم نامفهوم و عجیب غریب بود و میفهمیدمش ولی درکش نمیکردم توی جاوا اسکریپت همین synchronous و asynchronous بود :)با گشتن توی سطح اینترنت خوندن مقاله های مختلف تونستم چیزایی رو بفهمم که این دو تا مفهوم رو بتونم توی جاوا اسکریپت درک کنم و میخوام توی این مقاله واستون از چیزایی که فهمیدم در این مورد واستون توضیحاتی بدم که شما هم این دو مفهوم رو خیلی بهتر درک کنید. این مقاله شاید یکم طولانی باشه ولی به احتمال زیاد از خوندن این مقاله پشیمون نمیشید و مفهوم همگامی و ناهمگامی توی جاوا اسکریپت واستون جا میوفته. خب حرف بسه بریم سراغ توضیحات.بزارید الان خیلی ساده واستون معنی همگامی و ناهمگامی رو واستون توضیح بدم.با برنامه نویسی همگام یا synchronous شروع میکنم. این نوع از برنامه نویسی اینجوری هست که توی برنامه شما خط کد ها در هر شرایطی چه 10 دقیقه طول بکشه عملیاتش چه 1 ثانیه، دقیق پشت سر هم اجرا میشن. از خط یک به خط دو. از خط دو به خط سه و ادامه تا اینکه برنامه به جایی برسه که هیچ چیزی برای اجرا نداشته باشه. این سبک از برنامه نویسی یه سری معایبی داره که از جمله این معایب کندی برنامه هست، اتلاف بیهوده وقت، بلاک شدن برنامه و... هست. که البته جاوا اسکریپت هم جزو این دسته از زبون ها هست و اصولا single-thread هست(تک نخ. توضیح میدم در این مورد) برای مثال اگه شما بیاید و یه حلقه تعریف کنید که 10 میلیارد بار یه جمله رو لاگ بگیره، برنامه که چه عرض کنم، خود مرورگر هم به شدت هنگ میکنه و خط های بعد از اون حلقه اجرا نمیشن. که البته چیزی به نام web workers ها اومدن که سعی میکنم توی یه مقاله واستون توضیحش بدم. خب این از برنامه نویسی همگام یا synchronous یا سنکرون یا هرچیزی که شما دوست دارید صداش بزنید.حالا برنامه نویسی asynchronous یا ناهمگام چی هست؟ بزارید مثال قبل رو جوری بگم که انگار به صورت ناهمگام اجرا میشه. گفتیم اون حلقه که ده میلیارد بار یه چیزیو لاگ میگیره اگه به صورت سنکرون باشه، باعث میشه هم خود برنامه و هم خود مرورگر هنگ کنن و برنامه تون فلج بشه. حالا اگه اون برنامه رو به صورت اسنکرون بنویسیم، و اون حلقه رو بدیم به یه thread(نخ) دیگه، اون حلقه دیگه توی روند نخ اصلی برنامه مون دخالت نمیکنه و این باعث میشه برنامه مون به کار خودش توی نخ اصلی ادامه بده درحالی که توی یه نخ دیگه اون لوپ هی داره یه چیزیو لاگ میگیره. خب این خیلی خیلی چیز کاربردی ای هست و واقعا کمک میکنه توی سرعت بخشیدن به برنامه و جلوگیری از هنگ کردن بیخود. خب من توی مطالب قبل چند بار اسم thread(نخ) اوردم. ترد چی هست؟ ما یه ترد اصلی تو اجرای برنامه هامون داریم. بهش میگن main thread. برای اینکه یک سری دستورات رو جدا ازین ترد اجرا کنیم، باید ترد های دیکه ای بسازیم. پس ترد دقیقا چی هست؟ ترد به دستور العمل هایی میگن که به صورت مستقل توسط سی پی یو اجرا میشن. یعنی کد ها توی یه مسیر جدا از main thread و ترد های دیگه اجرا میشن و در نتیجه در روند اجراییشون اختلالی به وجود نمیاد. ترد ها به همدیگه دسترسی دارن. ترد مفهوم گسترده ای داره و من خیلی خیلی ساده گفتم بهتون. پس برای اطلاعات بیشتر از گوگل کمک بگیرید.تا اینجا امیدوارم با این مفاهیم کنار اومده باشید و تونسته باشید درک کنید این دو تا مفهوم مهم رو. بریم برای ادامه.مشکلات من ازونجایی شروع شد که شنیدم جاوا اسکریپت یه زبان اسنکرون هست و البته رو هوا هم نمیگفتن جاوا اسکریپت اسنکرون هست و مثال هایی از اون هم دیدم. خلاصه قاطی کرده بودم که چرا میگن جاوا اسکریپت اسنکرون هست درحالی که یک نخ بیشتر نداره. واقعا حسابی قاطی کرده بودم و درک نمیکردم چرا اینجوری هست تا اینکه بعد از سرچ های زیاد و مختلف و خوندن چند تا مقاله بالاخره فهمیدم چی به چی هست. بگذریم... بریم سراغ ادامه بحثمون.بزارید چند تا مثال از اینکه میگن جاوا اسکریپت اسنکرون هست واستون بزنیم.setTimeout(() => {console.log(&quot1&quot)}, 3000)console.log(&quot2&quot);دوستان فکر میکنید نتیجه این کد چه خواهد بود؟ اگر فکر میکنید نتیجه کد 1 و 2 خواهد بود، متاسفانه در اشتباه هستید. نتیجه این کد 2 و 1 خواهد بود. شاید بگید خب تو که گفتی جاوا اسکریپت سنکرون هست پس چرا این کدا به ترتیب اجرا نمیشن؟ بله هست و من هنوز پای حرفم هستم. الان دلیلشو واستون میگم.Call stackخب خب. این قسمت از مقاله قسمت بسیار جالب و جذابیه و خودم خیلی با فهمیدنش حال کردم و باعث شد نافهوم بودن سنکرون توی جی اس از بین بره واسم =)میدونید که جاوا اسکریپت یه زبان مفسری هست. میدونید که این زبان یک تردی هست. و توی مثال قبل هم که مثال خیلی کوچیکی هم بود دیدید که جاوا اسکریپت اون رو شبیه به یه زبان اسنکرون و چند تردی اجرا کرد. اما واقعیت چیه؟ بالاخره این زبان تک نخی هست یا چند نخی؟ سنکرون هست یا اسنکرون؟توی جاوا اسکریپت یه چیزی هست به اسم call stack(پشته فراخوانی). پشته چی هست؟ببینید ما توی برنامه مون از چیزای مختلفی استفاده میکنیم که فانکشن ها یکی از پر استفاده ترین هاشون هست. ما در اکثر مواقع فانکشن ها رو یه جا تعریف میکنیم و جایی که نیاز داریم ازشون استفاده میکنیم. وقتی شما فانکشن رو یه جایی صدا میزنید، جاوا اسکریپت میاد و این فانکشن رو میندازه جایی به اسم پشته فراخوانی. سپس اون رو اجرا میکنه و وقتی کار اون فانکشن تموم شد، میاد و اون رو از کال استک حذف میکنه. خب شاید زیاد نفهمیدید چی به چی شد. پایین واستون یه قطعه کد میزارم و بعد کال استک کد رو با تصویر بهتون نشون میدم.function sayHello() {console.log(&quothello&quot); }function sayHowAreYou(params) {console.log(&quothow are you?&quot);}function sayBye() {console.log(&quotbye!&quot);}sayHello();sayHowAreYou();sayBye();مراحل اجرا شدن به این شکل هست:1- مفسر شروع میکنه به خوندن قطعه کد ها.2- کد ها رو میخونه و میخونه و وقتی رسید به فراخوانی فانکشن sayHello، فانکشن رو میندازه توی کال استک.3- سپس مفسر میره برای خوندن قطعه کد های بدنه sayHello. در بدنه، به فراخوانی console.log برخورد میکنه. اینجا دستور لاگ رو هم میندازه توی کال استک.4- مفسر اینجا میاد و دستور لاگ رو انجام میده و سپس اون رو حذف میکنه از کال استک. و میره ادامه خوندن بدنه فانکشن sayHello. وقتی میبینه هیچ دستور دیگه ای برای اجرا نیست، فانکشن sayHello رو هم از کال استک حذف میکنه.پ.ن 1: این اتفاق برای فراخونی فانکشن های بعد از sayHello هم میوفته...پ.ن 2: یادتون باشه مفسر جاوا اسکریپت فانکشنای موجود توی استک رو از بالا به پایین اجرا میکنه!5- بعد اجرا شدن کل دستورات برنامه، کار مفسر تموم میشه و برنامه به پایان میرسه.و اینجوری برنامه ما اجرا میشه.خب بریم یکم مثالمونو پیچیده تر کنیم.function sayHello() {console.log(&quothello&quot);sayHowAreYou();}function sayHowAreYou(params) {console.log(&quothow are you?&quot);sayBye();}function sayBye() {console.log(&quotbye!&quot);}sayHello();خب توی این مثال اجزای برنامه دقیقا شبیه اجزای برنامه مثال قبلی هست. ولی این بار جور دیگه برنامه رو اجرا کردیم. توی گیف پایین میتونید وضعیت لحظه ای کال استک رو ببینید و پایین گیف هم متنی توضیح میدم چجوری این برنامه اجرا میشه.مرحله به مرحله واستون توضیح میدم که توی کال استک چه اتفاقی می افته:1- مفسر جاوا اسکریپت میاد و میبینه فانکشن sayHello فراخونی شده. اونو میندازه توی استک که بهش رسیدگی کنه.2- مفسر میبینه که متد console.log هم فراخونی شده توی بدنه sayHello. این متد رو هم میندازه توی استک که اجراش کنه.3- مفسر کار متد console.log که تموم شد، اون رو از استک حذف میکنه چون کاری باهاش نداره. بعد که میره خط بعد، میبینه که فانکشن sayHowAreYou فراخونی شده. به همین دلیل اون رو هم میندازه توی استک که بهش رسیدگی کنه.4- حالا مفسر میره دستورات فانکشن sayHowAreYou رو بخونه چون این فانکشن توی بالاترین قسمت استک قرار داره. وقتی داره خط های این فانکشنو میبینه، با متد console.log مواجه میشه و اون رو میندازه توی استک. بعد از مدت خیلی کمی مفسر اون متد رو هم اجرا میکنه و کارشو تموم میکنه.5- مفسر چون کار اجرای پردازش بالاترین متد استک ینی console.log رو تموم کرد، اون متد رو حذف میکنه. این در حالی هست که فانکشن های sayHello و sayHowAreYou هنوز کارشون تموم نشده و تو استک هستن. مفسر بعد ازینکه میره خط بعدی توی بدنه فانکشن sayHowAreYou میبینه که فانکشن sayBye فراخونی شده. این رو هم میندازه توی استک. الان سه تا فانکشن توی استک وجود داره.6- بعد مفسر میره توی بدنه فانکشن sayBye که دستورات دیگه رو تفسیر کنه. به console.log برخورد میکنه و اون رو میندازه تو استک. بعد که مفسر کارش تموم شد، اون رو از کال استک حذف میکنه.7- بعد مفسر میره ببینه کاری توی sayBye نمونده، که متوجه میشه کار دیگه ای نمونده. به همین دلیل sayBye رو حذف میکنه از استک. حالا چون sayHowAreYou در بالاترین قسمت استک هست، اون رو هم چک میکنه و میبینه کار دیگه ای نمونده. به همین دلیل اون رو هم پاک میکنه از استک. الان توی بالاترین قسمت استک sayHello مونده. مفسر اون رو هم چک میکنه و میبینه اونجا هم کاری نیست. به همین دلیل sayHello رو هم از استک حذف میکنه و بدین ترتیب استک خالی میشه و برنامه هم به پایان میرسه.همیشه موقع کد زدن حواستون به استک هم باشه که بیهوده و زیادی پرش نکنید. اگر استک پر بشه با ارور stack overflow مواجه میشید. خب امیدوارم قسمت کال استک رو خوب متوجه شده باشید. بریم سراغ ادامه. در ادامه متوجه سنکرون بودن جاوا اسکریپت میشید.Callback Queue یا Task Queueتوی جاوا اسکریپت، بعضی از متدایی که استفاده میکنیم، مال api خود browser(مرورگر) هستن. بهش هم web apis میگن، هم browser apis. متد هایی مثل setTimeOut یا مثل XMLHttpRequest و ککللییی متد دیگه مربوط به web apis هست.اینجا میتونید لیست کاملی از متد های web apis رو ببینید که ماشالا تعدادشون هم زیاده.توی جاوا اسکریپت یه چیزی هست به اسم callBack(بازگشت فراخوانی. خواهشا اینطوری صداش نزنید و انگلیسیشو بگید). خب کالبک چی هست؟ کالبک فانکشن ها به فانکشن هایی میگن که به عنوان آرگومان به یه فانکشن دیگه داده میشه و بعد از انجام شدن عملیات ناهمگام(بیشتر واسه عملیات ناهمگام استفاده میشه) اون فانکشن، کال بک فانکشن اجرا میشه و این باعث میشه که عملیات ناهمگام مدیریت بشن. اوایل مقاله یه مثال واستون زدم ازینجور عملیات. یادتون هست؟ الان میخوام با کالبک فانکشن اون مشکل که عدد 2 زودتر از 1 نمایش داده میشد رو حل کنم.setTimeout(() => {console.log(&quot1&quot)}, 3000)console.log(&quot2&quot); //output: //2 //1 function callBack() { console.log(&quot1&quot); console.log(&quot2&quot) } setTimeout(callBack, 3000); //output: //1 //2 متد setTimeout دو تا آرگومان میگیره. یکیش یه کالبک فانکشن هست و دومی تایم اجرای اون کالبک فانکشن. چرا ما کالبک فانکشن میدیم به setTimeout؟ چون میخوایم بعد از انجام شدن عملیات setTimeout فانکشن ما اجرا بشه.توی کد بالا، اول کد مثال اول مقاله رو نوشتم. اگه دقت کنید من به setTimeout یه کالبک فانکشن به عنوان آرگومان پاس دادم. توی کد بعدیش ما مشکلمون رو حل کردیم. این دفعه من برای اینکه یه وقت قاطی نکنید یه فانکشن ساختم به نام callBack و اون رو پاس دادیم به setTimeout که بعد از گذشت 3 ثانیه فانکشنمون درست اجرا بشه و به ترتیب عدد 1 و 2 رو لاگ بگیره. ما میتونستیم همون فانکشن رو توی آرگومان setTimeout تعریف کنیم.پس گفتیم کالبک ها فانکشن هایی هستن که میخوایم بعد از اجرای یه عملیات ناهمگام اجرا بشن!میرسیم به قسمت خیلی مهم مقاله که سنکرون بودن جاوا اسکریپت واستون جا میوفته.گفتیم که ما یه چیزی داریم به اسم web apis و یه چیزی داریم به نام call back. توی جاوا اسکریپت یه مخزن دیگه هست که بهش میگن callBack queue(صف کالبک) که بهش task queue(صف کار) هم میگن.توی کالبک کیو، کالبک فانکشن هایی که میخوایم بعد از اجرا شدن متد های browser apis اجرا بشن قرار میگیرن.بزارین با یه مثال دقیق تر واستون توضیح بدم web apis و call back queue رو.setTimeout(() => {console.log(&quotcall stack is free. say hello to call back function.&quot)}, 2000)console.log(&quotcall stack is full&quot)مثال کوچیک ولی مفیدی هست چون با این مثال میخوام توضیحات تکمیلی رو بدم.توی پشت صحنه جاوا اسکریپت یه چیزی هست به اسم event loop(چرخه رویداد). ایونت لوپ مدام در حال چک کردن کال استک و کالبک کیو و چیزای دیگه هست. ایونت لوپ میاد و چک میکنه اگه کال استک خالی بود، و اگه کالبک کیو حداقل یه فانکشن داشت، اون کالبک رو میندازه توی کال استک که اجرا بشه.دقت کنید اجرا شدن فانکشن های توی call stack از اولویت بالاتری برخوردار هست و تا وقتی کال استک خالی نباشه، کالبک فانکشن نمیتونه اجرا بشه.خب من واستون متنی هم توضیح میدم مثالی که من واستون زدم. ولی به گیف هم دقت بکنید حتما. 1- مفسر میاد و از خط اول شروع میکنه و بعد با اولین متد که setTimeout هست مواجه میشه. اونو میندازه تو استک و بعد ایونت لوپ که گفتیم مدام داره بررسی میکنه، میفهمه که اون متد مربوط به وب ای پی آی هاست و به همین دلیل ورش میداره و میندازتش توی قسمت وب ای پی آی.2- اونجاست که وب ای پی آی یه تایمر دو ثانیه ای ست میکنه که اون فانکشن ناشناسی(anonymous function) که ما بهش پاس دادیم رو بعد ازینکه تایمر تموم شد ایونت لوپ بندازتش تو کالبک کیو.3- مفسر خط های بعد رو میره میخونه و با console.log مواجه میشه. اون رو میندازه توی کال استک تا اجراش کنه. وقتی اجراش کرد اون رو از استک حذف میکنه.4- الان استک خالی هست و وب ای پی آی تایمرش تموم شده و ایونت لوپ کالبک فانکشن رو انداخته توی کالبک کیو. به همین دلیل وقتی ایونت لوپ میرسه به کالبک کیو، و میفهمه که استک خالی هست، فانکشن ناشناس ما رو میندازه توی استک که اجرا بشه. وقتی مفسر میره توی بدنه فانکشن، دوباره با console.log مواجه میشه و اونو میندازه تو استک. و وقتی اجراش کرد اون رو حذف میکنه و چون فانکشن ما به پایان رسیده اون رو هم از استک حذف میکنه و برنامه به پایان میرسه.الان دیگه فکر کنم متوجه شدید چرا جاوا اسکریپت سنکرون هست ولی بعضی از دستور هاش به صورت اسنکرون اجرا میشه و اسنکرون بودن رو شبیه سازی میکنن :)setTimeout(() => {console.log(&quot1&quot)}, 0)console.log(&quot2&quot)حالا شما بگید خروجی این کد چی هست.promiseتوی جاوا اسکریپت یه چیزی هست به اسم promise. چون یه چیز دیگه مثل کالبک کیو توی جاوا اسکریپت هست و مربوط به پرامیس ها هست، یکم از پرامیس ها هم حرف میزنم ولی کامل نیست و سعی میکنم یه مقاله کامل راجع بهش بنویسم و اینجا هم حتما لینکشو خواهم گزاشت.خب پرامیس رو چجوری میشه تعریف کرد؟ اینجوری:let myPromise = new Promise((resolve, reject) => {resolve(&quothey! the promise was successful&quot)});برای ساخت میتونیم از کلاس پرامیس استفاده کنیم که متد سازنده این کلاس، به یه executor function(تابع مجری. من همون اگزکیوتر صداش میزنم) نیاز داره که حداقل باید شامل یک آرگومان باشه. آرگومان اولی برای فرستادن اطلاعات در صورت موفق بودن عملیات هست، آرگومان دوم برای فرستادن اطلاعات یا ارور یا هرچیز دیگه ای در صورت شکست عملیات هست. تو این مقاله من فرض میکنم عملیات همیشه موفق هست.برای اعلام شکست عملیات، باید reject رو فراخوانی کرد و برای اعلام موفقیت برنامه باید resolve رو فراخونی کرد.حالا برای دریافت اطلاعات در صورت موفق بودن اجرا توی پرامیس باید چیکار کرد؟ باید از .then() استفاده کرد. برای دریافت اطلاعات در صورت شکست هم باید از .catch() استفاده کرد. این دو تا متد هم هرکدومشون یه آرگومان باید داشته باشن که اطلاعات موفقیت یا شکست توی اون آرگومان ذخیره میشه. به این شکل:myPromise.then((success_value) => {console.log(success_value);}); //outputکلا وقتی دیدن کالبک فانکشن ها بعضی جاها خیلی پیچیدگی و ناخوانایی به وجود میاره و خیلی دیباگ کردن در بعضی مواقع سخت میکنه، اومدن و پرامیس ها رو اوردن که خیلی تاثیرات مثبتی داشتن توی کد و تقریبا مثل کالبک فانکشن ها عمل میکنن. البته هنوز هم از کالبک فانکشن ها استفاده میشه. مثلا توی حلقه forEach. هنوز هم خیلی استفاده میشه چون همونطور که گفتم در بعضی مواقع پیچیدگی و ناخوانایی اضافه میکنه به کد. برای دیدن نمونه ای ازین پیچیدگی های وحشتناک، عبارت callBack hell رو گوگل کنید.یه چیز دیگه رو که نیاز هست توضیح بدم اینه که مفسر وقتی به پرامیس برخورد میکنه، درجا اگزکیوتر فانکشنشو میندازه توی کال استک و اجراش میکنه. برای مثال اینجا رو ببینید:let myPromise = new Promise((resolve, reject) => { console.log(&quothaha you didnt use .then() but im running!&quot)resolve(&quothey! the promise was successful&quot)}); console.log(&quotthere is a text before me!&quot) همونطور که گفتم مفسر وقتی داره خط ها رو میخونه، اگه به پرامیس برخورد کنه، درجا اگزکیوتر فانکشنشو میندازه توی کال استک و وقتی کار اگزکیوتر فانکشن تموم شد اون رو از کال استک حذف میکنه. و بعدش میره سراغ console.log دوم و کارای اون رو انجام میده.توی جاوا اسکریپت یه چیز دیگه مثل کالبک کیو هست به اسم job queue(صف کار). این صف مختص پرامیس ها هست. فانکشنی که شما پاس میدید به .then یا .catch، انداخته میشن توی جاب کیو و دقت کنید «فقط وقتی فانکشن های توی جاب کیو اجرا میشن به ترتیب، که کال استک خالی خالی باشه».بزارید اولویت اجرایی یه برنامه رو به ترتیب بهتون بگم:1- کال استک2- جاب کیو3- کالبک کیوپس اگه دیدید فانکشن های جاب کیو زودتر اجرا شدن تعجب نکنید چون این به دلیل اولویت هست.یه چیز جالب دیگه که باید بگم این هست که توی پرامیس وقتی یه چیزی ریزالو یا ریجکت میشه، درجا اون فانکشن پاس شده شما به .catch یا .then اضافه میشه به جاب کیو. و بعد برنامه ادامه پیدا میکنه تا وقتی کال استک تموم بشه. بعدش که تموم شد تک تک آیتمای جاب کیو به ترتیب انداخته و اجرا میشن توی کال استک. resolve حکم صدا زدن کالبک واسه ما داره.بزارید واستون مثال بزنم.let myPromise1 = new Promise((resolve, reject) => {console.log(&quothey! im the first promise&quot)resolve(&quota message from promise1!&quot)})let myPromise2 = new Promise((resolve, reject) => {console.log(&quothey! im the second promise&quot)resolve(&quota message from promise2!&quot)})function getResolve1() {myPromise1.then(function run1(value) {console.log(value)});getResolve2()}function getResolve2() {myPromise2.then(function run2(value) {console.log(value)});} getResolve1() خب. گفتیم مفسر تا به پرامیس برخورد کرد، اگزکیوتر فانکشنشو اجرا میکنه و توی اگزکیوتر فانکشن وقتی برسه به resolve درجا فانکشنی که پاس دادیم به .then مربوطه رو میندازه توی جاب کیو.خب قدم به قدم واستون توضیح میدم طرز اجرا شدن این برنامه رو:1- مفسر به پرامیس اول برخورد میکنه. اگزکیوتر فانکشنشو میندازه توی کال استک و بعد توی بدنه، به دستور لاگ برخورد میکنه. اون رو هم میندازه توی کال استک و اجرا میکنه و بعد حذف میکنه و بعدش به ریزالو برخورد میکنه. اینجا هست که فانشکن run1 توی جاب کیو انداخته میشه.2- توی خط بعدی که پرامیس دوم رو تعریف کردیم هم همینطوری اجرا میشه و وقتی توی اگزکیوتر فانکشن به ریزالو برخورد میکنه فانکشن run2 انداخته میشه توی جاب کیو و بعد که به پایان اگزکیوتر فانکشن رسید، اگزکیوتر فانکشن رو از کال استک رو حذف میکنه. پس تا اینجا توی جاب کیو، دو تا فانکشن run1 و run2 هست.3- برنامه ادامه پیدا میکنه تا اینکه برسه به getResolve1. بعدش اون فانکشن رو میندازه توی کال استک. گفتیم که دستور .then اجرا شده. پس میره خط بعدی و اینجا به getResolve2 برخورد میکنه. اون رو هم میندازه توی کال استک. توی این فانکشن هم .then اجرا شده. اینجاست که برنامه ما تقریبا تموم شده. پس میاد فانکشن های getResolve1 و getResolve2 رو حذف میکنه.4- ایونت لوپ میبینه که توی جاب کیو دو تا فانکشن هست. پس میاد از سمت راست به چپ(قدیم به جدید)، اون ها رو میندازه توی کال استک. اول فانکشن run1 انداخته میشه توی کال استک. مفسر میره برای اجرا. دستور لاگ رو میبینه. اون رو هم میندازه توی کال استک و اجراش میکنه. بعد دستور لاگ رو حذف میکنه. بعد که ایونت لوپ میبینه run1 تموم شده اون رو هم حذف میکنه. و برای run2 هم همینجوری هست دقیقا. بعد از اجرای run2، برنامه به پایان میرسه.و این هم از این مقاله :)قبل ازینکه مقاله رو رسما به پایان برسونم جا داره دو تا سایت رو برای انجام تست اجرا بهتون معرفی کنم که قدم به قدم بهتون نشون میده چجوری اجرا میشه یه برنامه و میتونید کد مثال های من رو هم کپی کنید و اونجا ببینید چگونگی اجرا شو.سایت اول: https://www.jsv9000.app/سایت دوم: http://latentflip.com/loupeالبته هرکدوم از این سایت ها یه سری چیز ها رو کم دارن ولی برای یادگیری عالی هستن. مثلا سایت اول قسمت web apis رو نداره و console.log رو نمینندازه توی کال استک. سایت دوم web apis رو داره ولی از پرامیس ها پشتیبانی نمیکنه و فانکشن هاتون باید معمولی باشه نه به شکل arrow. و رسیدیم به پایان مقاله. سعی کردم مفهوم همگام بودن و ناهمگام بودن جاوا اسکریپت رو واستون توضیح بدم نه اینکه صرفا بگم همگام میشه این، ناهمگام میشه اون. و همچنین بهتون راه های مقابله با این ناهمگامی رو هم بگم بهتون که با معرفی پرامیس ها و کالبک ها این ها رو هم گفتم.خب امیدوارم از این مقاله خوشتون اومده باشه و مفهوم همگام و ناهمگام بودن جاوا اسکریپت رو واستون جا انداخته باشم. اگه دوست داشتید لایک کنید مقاله مو. اگه دوست داشتید دنبال کنید من رو. اگه دوست داشتید یه کامنت مثبت و یا انتقاد منطقی بزارید واسم. خلاصه هرکاری دوست داشتید توی زندگیتون انجام بدید؛ هرکاری که به کسی آسیب نزنه و یا غمگینش نکنه :)