How does JavaScript runtime work

Thet Khine
4 min readJan 12, 2021

JavaScript က နေရာတိုင်းမှာ သုံးလာတယ် အသုံးဝင်လာတယ်။ Backend မှာ Node.js , front end ဘက်မှာ Angular, React, Mobile ဘက်မှာ React Native, Ionic နောက် desktop ဘက်မှာ electron အစရှိတာတွေဟာ JS Framework တွေချည်းပဲ။ Node.js ဆိုရင်သူက Google ရဲ. Chrome browser မှာ သုံးတဲ့ v8 ဆိုတဲ့ JavaScript Engine ကိုသုံးထားတာ။ ဒီနေရာမှာ Developer တွေ က Web Browser ဆိုတာရယ် Rendering Engine ဆိုတာရယ် JavaScript Engine ဆိုတာရယ်ကို ကွဲတယ်လို.မထင်ဘူး။ Browser တွေဘယ်လိုအလုပ်လုပ်သလဲဆိုတာ ဒီမှာရေးထားဖူးတယ်။

Developer တွေမျက်စိနဲ.မြင်နေရတာက Browser တခုတည်း ဒါကြောင့်ခုနက Browser Engine, Rendering Engine နဲ. JavaScript Engine သုံးခုကို မသဲကွဲတာ။ တကယ်တော့ Browser တခုလို. ဆိုလိုက်ရင် ခုနက သုံးခုပေါင်းမှ တခုဖြစ်တာ။ ဒီနေရာမှာ တချို.က browser engine နဲ. rendering engine ကိုတွဲသုံးကြသေးတယ်။ သူတို.ရဲ. အဓိက အလုပ်က HTML , CSS makup တွေကို layout ချမယ် screen ပေါ်မှာပေါ်လာအောင် rendering လုပ်မယ်။ Rendering engnine ကို layout engine လို.လဲခေါ်သေးတယ်။ Rendering engine တွေကို သက်သက် ယူသုံးလို.ရတယ်။ ဥပမာ Apple Safari မှာ WebKit ကိုသုံးတယ် နောက် PhantomJS မှာလဲသုံးတယ်။ IE မှာတော့ Trident ဆိုတဲ့ rendering engine ကိုသုံးတယ်။ ခုနက rendering engine ရဲ.အလုပ်သည် UI element တွေကို web element တွေကို display ပြတာပဲလုပ်တာ။ အဲ့တော့ JavaScript code တွေ run ဖို.ဘယ်သူကလုပ်ရသလဲဆိုရင် JavaScript Engine ကလုပ်ရတယ်။ ဥပမာ Chrome မှာ Blink rendering engine ကိုသုံးတယ်သူ.က WebKit ရဲ. WebCore Component ကို fork လုပ်ထားတာ။ Chrome မှာ JavaScript Engine အနေနဲ.ကျတော့ V8 ဆိုတာကိုသုံးတယ်။ နောက် Node.js မှာလဲ v8 ကိုသုံးတယ်။ Apple Safari မှာဆိုရင် Nitro ဆိုတဲ့ JavaScript Engine ဆိုတာကိုသုံးတယ်။ အဲ့တော့ Developer တွေနဲ. JavaScript ရေးတဲ့အခါ code optimization လုပ်တဲ့အခါအတော်လက်ဝင်တယ်။ ဥပမာ Chrome မှာ Optimized code က Safari မှာ opimized ဖြစ်ချင်မှဖြစ်မယ်။ ဒါကိုဆိုချင်တာ။

JavaScript က dynamic language , သူ.ကို interpret လုပ်တယ်လို.လဲသိကြတယ်။ Interpret လုပ်တယ်လို.ဆိုရင် browser အားလုံးမှာ မမှန်ဘူး ။ ဘာလို.လဲဆိုတော့ Chrome v8 ရော Nitro ရောမှာ JIT compilation တွေ JavaScript code ကနေ native machine code ပြောင်းတာတွေလုပ်ထားကြတာကြာပြီ။ ပြောရရင် modern JavaScript runtime တော်တော်များများသည် JavaScript to native machine code compilation ကိုလုပ်ကြရတယ်။ Language အနေနဲ.ကြည့်ရင်တော့ interpret လုပ်သွားတယ် ဆိုတာဟုတ်တယ်။ line by line execute လုပ်တယ်။ လိုအပ်တော့မှ parse လုပ်ပြီး execute လုပ်တယ်။ တခါတလေ ခနခန ပြန် parse မလုပ်ပဲ cache လုပ်ထားတာလဲရှိတယ်။ နောက် implementation ဘက်မှာကျတော့ JavaScript code တွေကို interpreter မသုံးပဲ အထဲမှာ JavaScript ကနေ intermeidate form ကိုပြောင်းမယ် အဲ့ကနေ native code ကိုပြောင်းပြီး compile လုပ်မယ်. အဲ့လိုလုပ်ကြတယ်။ ဒါကြောင့်များသောအားဖြင့် implementation အရဆို interpret လုပ်တယ်လို.ဆိုလို.မရပြန်ဘူး။ Hybrid apporach တွေလဲရှိတယ်။ JIT(Just in time compilation ) ဥပမာ code တခုကို run တော့မယ်ဆိုမှ သူ.ကို native machine code ပြောင်းပစ်တာမျိုး။ နောက် AOT (Ahead of time compilation) သူက code ကိုမ run ခင်ကတည်းက ကြိုပြီး native code ပြောင်းထားတာမျိး။ ဘယ်လို code တွေကို AOT လုပ်သလဲဆိုရင် ခနခန run တဲ့ hot method တွေကို AOTသုံးပြီး native machine code ပြောင်းလေ့ရှိတယ်။ Native machine code နဲ.အထဲမှာ run ရတဲ့အတွက် speed သည်တက်လာတယ်။ ဒါပေမဲ့ C/C++ လို speed တော့မရသေးဘူး ဘာလို.လဲဆိုတော့ runtime မှာ JavaScript ကနေ Machine code ကိုပြန်ပြောင်းနေရတဲ့ compilation process ရှိနေလို.။ နောက် dynamic langauge ဖြစ်တဲ့အတွက် Object တွေမှာ attribute တွေထဲ့မယ် ပြောင်းမယ် မှတ်မယ်ဒါမျိုးကို compiler တွေ အနောက်မှာ machine code ထုတ်တဲ့အခါ deferencing သုံးရတယ်။ ဥပမာ ဆိုကြပါဆို. a+b ဆိုပါစို. a နဲ. b သည် အားလုံးဖြစ်နိုင်တယ်။ အဲ့တော့ Java, C မှာလို integer အပေါင်း string concatenation တခါတည်းတန်းမသိဘူး။ Runtime ရောက်တော့မှ a ရယ် b ရယ်အပေါ်မူတည်ပြီး native machine code ထုတ်ရတယ်။ ဒါတွေကြောင့်လဲ လေးတယ်။

နောက်တခုက DOM access code, browser ကပေးထားတဲ့ Global object တွေနဲ. JavaScript engine ကပေးထားတဲ့ဟာတွေမတူဘူး။ ဥပမာ document.getElementById ဒါမျိုးဆိုရင် DOM ကို access လုပ်ရတာ အဲ့ဒီ API သည် JavaScript Engine မှာ မပါဘူး။ Browser ကနေပေးထားရတာ ။ အဲ့ဒီတော့ JavaScript engine ကနေ Browser DOM API ကို လှမ်းခေါ်ရတယ်။ နောက် Dom ပြောင်းသွားရင် rendering engine သည် layout ကိုပြောင်းပစ်ရမယ်။ ဒါမျိုးကို page reflow လို.ခေါ်တယ်။ Web page တခုမှာရှိတဲ့ css attribute လေးတခုပြောင်းလိုက်ရုံနဲ. web page layout ကိုပြန်တွက်ရတယ် အဲ့ဒီအတွက် cost ကုန်တယ်။ ဒါကြောင့် DOM code တွေသည် နှေးတယ်ဆိုတာဖြစ်ကုန်တာ။ JavaScript Runtime လို.ပြောလိုက်ရင် သူ.မှာ Memory area တွေပါမယ်။ ဥပမာ Stack , Heap တွေ နောက် Heap ကို manage လုပ်ဖို. GC Garabage Collection algorithm တွေပါမယ်။ GC တွေကလဲ JavaScript engine တခုနဲ.တခုမတူကြဘူး။ နောက် JavaScript ကို compilation လုပ်ဖို. JIT, AOT compiler တွေပါမယ်။ နောက် Global variable တွေ အစရှိတာတွေမှတ်ဖို. execution context ဆိုတာပါမယ်။ Execution context က တခုထက်မကရှိနိုင်တယ်။ GC ကတော့ execution context အားလုံးက အတူတူသုံးကြရတယ်။ ဥပမာ browser တခုမှာ Iframe တွေပါလာပြီဆိုရင် multiple execution context ဖြစ်နိုင်တယ်။ ဒါပေသိသူတို.အားလုံးက GC တွေ JIT, AOT တွေကိုအကုန် အတူတူ share လုပ်ပြီးသုံးကြရတယ်။

JavaScript က တခြား language တွေနဲ.မတူတဲ့အချက်က single threaded language ဖြစ်တယ်။ အဲ့တော့ JavaScript runtime တခုမှာ thread တခုပဲရှိတယ်။ Java, C# မှာဆိုရင် multiple execution thread တွေရှိတယ်။ Thread တခုချင်းဆီမှာ သူတို.နဲသက်ဆိုင်ရာ method call stack တွေရှိမယ်။ Method call stack ဆိုတာ method တခု function တခုခေါ်ပြီဆိုရင် function အတွက်လိုအပ်တဲ့ variable တွေ runtime data structure တွေ ပါတဲ့ stack frame တခုကို ခုနက method call stack ပေါ်ကိုတင်ရတယ်။ Function ပြီးသွားရင် ခုနက method call stack ပေါ်ကနေ stack frame ကိုပြန်ပြီး pop လုပ်ရတယ်။ ဒီနည်းနဲ. ဘယ် method ပြီးရင် ဘယ် method ကို return ပြန်ရမယ်ဆိုတာကို runtime ကသိတာ။ Single thread နဲ. run နေတဲ့အတွက် function တခုကနေ computational time ကိုအကြာကြီးယူထားမိရင် ဥပမာ loop ကို အများကြီးပတ်လိုက်တယ်ဆိုပါစို.ဒါဆိုအချိန်ကြာသွားမယ်။ အဲ့ဒီကျရင် browser မှာ unrepsonive JS error တက်လာလိမ့်မယ်။ ဒါဆိုရင် long compuation တွက်ချင်ရင် ဘာလုပ်ရမလဲဆိုရင် အပိုင်းအပိုင်းလေးတွေ ခွဲပြီး တခုချင်းပြန် run ရတယ်။ SetInterval တို. setTimeout တို.ကိုဘယ်လို schedule လုပ်သွားသလဲဆိုတာကိုနားလည်ဖို.ကျတော့ JavaScript ရဲ. Concurrency model နဲ. event loop ဆိုတာကို နားလည်ရမယ်။

JavaScript memory ကို ခွဲလိုက်ရင် သုံးမျိုးရမယ်။ Stack (ဒါက method calling လုပ်တဲ့အခါ method တခုခြင်းရဲ. stack frame တွေကိုသိမ်းထားတာ ) , Heap (သူကတော့ JavaScript object တွေကို သိမ်းတဲ့နေရာ. user define လဲဖြစ်ချင်ဖြစ်မယ်။ system define လဲဖြစ်ချင်ဖြစ်မယ်။) ဥပမာ var a = new Date(); ဒါကို run မယ်ဆိုရင် memory ပေါ်မှာ Date constructor ကို run ဖို. stack frame ပေါ် frame တခုတင်ရမယ်။ နောက် date object အတွက် ကျတော့ heap ပေါ်မှာလိုအပ်တဲ့ memory ပမာဏကိုယူရမယ်။

နောက်ဆုံးတခုက Queue, Queue ကကျတော့ အခု CPU ပေါ်မှာ run နေတဲ့ method တွေမရှိတော့ဘူး နည်းသွားပြီဆိုရင် queue ထဲမှာစောင့်နေတဲ့ task တွေကို run ဖို.လုပ်ထားတာ ။ ဥပမာ setInterval နဲ.ခေါ်ထားတဲ့ method တွေဆိုရင် queue ထဲဝင်သွားမယ်။ အချိန်ရရင် scheduler ကနေ queue ထဲကကောင်တွေကို run တယ်။ ဒီနည်းနဲ. single thread မှာ setInterval, setTimeout , event တွေကို process လုပ်သွားတာ။

Event Loop ဆိုတာ JavaScript queue ရဲ. အလုပ်လုပ်တဲ့ပုံကိုပြတာ

while (queue.waitForMessage())
{
queue.processNextMessage();
}

ဒီလိုလုပ်သွားတာ။ queue ထဲမှာလုပ်စရာရှိရင် လုပ်တယ်။ မရှိရင် စောင့်နေတယ်။ တခြားအလုပ်တွေလုပ်တယ်ပေါ့။ Chrome ရဲ. V8 လို JIT AOT အဆင့်ဆင့်ပါတဲ့ကောင်တွေမှာ JavaScript code ကနေတန်းပြီး interpret မလုပ်ဘူး။ Native code ပြောင်းပြီးမှလုပ်တယ်။ နောက် တခြား JS engine specific optimization တွေရှိသေးတယ်။ ဥပမာ V8 မှာဆိုရင် JavaScript Object တခုကို rutime မှာ hidden class တခုအနေနဲ.သိမ်းထားတယ်။ နောက်တချိန် အဲ့ဒီ Object ကို attribute တွေထပ်မထဲ့ရင် v8 က ခုနက Object ရဲ. field တွေ method တွေ access လုပ်တဲ့ကောင်မျိုးကို optimized လုပ်နိုင်တယ်။ အဲ့လိုမျိုးရေးတာကို monomorphism လို.ခေါ်တယ်။ Dynamic language ရေးပေမဲ့ Polymorphic data structure သုံးတာ များရင် engine အပေါ်မူတည်ပြီး optimization ကောင်းကောင်းမရနိုင်ဘူး။

--

--