Si funksionon Javascript?

JavaScript është një gjuhë sinkrone me një fillesë, që do të thotë se ka një Stack të vetëm thirrjesh. Prandaj mund të bëjë vetëm një gjë në të njëjtën kohë.

Koncepti themelor i JavaScript është Konteksti i Ekzekutimit. Gjithçka në JavaScript ndodh brenda kësaj. Konteksti i ekzekutimit mund të konsiderohet si një enë me 2 komponentë:

1. Mjedisi i ndryshueshëm ose grumbulli i memories
2. Fija e ekzekutimit ose grupi i ekzekutimit

Mjedisi i variablave ruan të gjitha variablat dhe funksionet. Është një çift çelës-vlerë ku ruhen të gjitha variablat e deklaruara dhe vlerat e tyre. Gjithashtu këtu ruhen edhe emrat e funksioneve dhe kodi i tyre përkatës.
Komponenti i dytë i quajtur filli i ekzekutimit është vendi ku
ekzekutohet kodi, me një rresht të vetëm. JavaScript mund të kalojë në rreshtin tjetër të kodit vetëm pas ekzekutimit të rreshtit të parë të kodit. Kjo është sjellja sinkrone e ekzekutimit me një fillesë të JavaScript.

Ekzistojnë dy lloje të kontekstit të ekzekutimit në JavaScript:

  1. Konteksti Global i Ekzekutimit, GEC
  2. Konteksti i ekzekutimit të funksionit, FEC

GEC është konteksti i paracaktuar ku ekzekutohen të gjitha kodet që nuk janë brenda një funksioni. Dhe FEC krijohet brenda kontekstit të ekzekutimit Global/Default sa herë që thirret një funksion.

Le të shkojmë pak më thellë

Steku i telefonatave
Steku i thirrjeve është një strukturë bazë e të dhënave të stivës me operacione push dhe pop.
Pra, kur ne jemi duke ekzekutuar një funksion, konteksti i ekzekutimit shtyhet në krye të stivit dhe shfaqet kur përfundojmë ekzekutimin. Çdo hyrje e shtyrë në pirg quhet kornizë e pirgut.

Pra, fillimisht stack do të jetë bosh dhe kur motori të fillojë, hyrjet do të shtohen në pirg gjatë ekzekutimit. Le të kemi një shembull,

const firstFunction = () => {
  const param = secondFunction()
  console.log(param)
}
const secondFunction = () => {
  return 'print-me'
}
firstFunction()

Kur ndodh një përjashtim, mesazhi i gabimit do të tregojë gjurmën e stivës së ekzekutimit, në thelb është fotografia e pirgut në atë moment të veçantë.

Gabimi i mëposhtëm do të ndodhë kur kam bërë një gabim shtypi në kodin e mësipërm.

Kjo është një pamje e qartë e statusit aktual të pirgut të ekzekutimit. Kjo e ndihmon zhvilluesin në korrigjimin e kodit kur ndodh një përjashtim.

Menaxhimi i kujtesës
Edhe pse motori JavaScript merret me menaxhimin e kujtesës, herë pas here ne mund të hasim në probleme si rrjedhjet e kujtesës të cilat mund të zgjidhen vetëm nëse dimë se si menaxhohet memoria në JavaScript motorri.

Cikli jetësor i memories në JavaScript ka 3 faza
1. Alokimi i memories
2. Përdorimi i memories
3. Lirimi i memories

Sa herë që krijojmë një variabël ose funksion, motori JavaScript shpërndan memorie për ta dhe do të lëshohet kur të mos jetë më e nevojshme.

Motori përdor një strukturë të dhënash Stack and Heap bazuar në faktin nëse e njeh kërkesën e memories në kohën e përpilimit apo jo. Nëse përdorimi i memories është i përcaktuar, motori do të përdorë shpërndarjen statike të memories duke përdorur strukturën e të dhënave të stivës dhe nëse jo përdor strukturën e të dhënave të grumbullit që quhet alokim dinamik i memories.

Alokimi statik i memories përdoret për variablat primitive dhe dinamika përdoret për objektet, vargjet dhe funksionet. Le të kemi një shembull,

const posts = {
  id: 1,
  name: 'How JavaScript works?'
}
const comments = {
  comment: 'JavaScript is a wierd language',
  postId: 1
}
const getCommentsWithPostId = (id) => {
  return comments.find(item => {
    return item.postId === id
  })
}
let postId = 1
getCommentsWithPostId(postId)

Në këtë shembull,
posts comments getCommentsWithPostId do të shkojë në Head dhe postId do të shkojë në rafte. Por çdo hyrje e Grumbullit do të ketë një referencë në pirg.
Meqenëse përmbajtja në Grumbull nuk është renditur në ndonjë mënyrë të veçantë, ne duhet të shtojmë një referencë për Grumbull nga Stack.

Përdorimi i kujtesës është në thelb operacioni i leximit dhe i shkrimit në kodin JavaScript.

Hapi i fundit i menaxhimit të kujtesës është Lëshimiose i quajtur gjerësisht Grumbullimi i mbeturinave. Ashtu si shpërndarja e memories, motori JavaScript trajton gjithashtu lëshimin e memories, nëpërmjet Garbage Collector.
Identifikimi se kur duhet lëshuar memoria është një problem tjetër, nuk ka asnjë Algoritëm të vetëm që e lëshon menjëherë memorien kur referenca bëhet e vjetëruar. Shënimi i referencës dhe algoritmi i shënjimit dhe fshirjes janë dy algoritme të mbledhjes së mbeturinave që i japin një përafrim të mirë këtij problemi.

Ky problem i vendimmarrjes është shkaku i rrjedhjes së kujtesës në JavaScript.
Disa natyrë ciklike të JavaScript-it heqin referencën në pirg, por vlera aktuale do të mbetet në grumbull.
Një kuptim i mirë i menaxhimit të kujtesës në JavaScript ndihmon për të shkruar kod të pastër me më pak shanse për rrjedhje të memories.

Çfarë është rrjedhja e kujtesës?
Mund të konsiderohet si pjesë e memories që nuk kërkohen më për aplikacionin, por për ndonjë arsye nuk lëshohen përsëri në grupin e memories së sistemit operativ. Një lak i pafund ku ne po i shtojmë vlera një ndryshoreje është një shembull i kësaj, pasi mbledhësi i mbeturinave nuk do të funksionojë pasi variablat vazhdojnë të përdoren. Le të kemi një shembull

let randomArray = [
for(let i = 0 ; i > 1 ; ++i) {
  randomArray.push(i)
}

Këtu mbledhësi i mbeturinave nuk do të funksionojë pasi grupi randomArray po përdoret nga aplikacioni, i cili po shtyn vlerën e i në grup.

Tani le të shqyrtojmë disa çështje të tjera të rrjedhjes së kujtesës dhe të shohim se si të kuptuarit e menaxhimit të kujtesës na ndihmon t'i shmangim ato lehtësisht.

Rrjedhja më e zakonshme e kujtesës në JavsScript është ruajtja e vlerave në variabla globale ose përdorimi i variablave të padeklaruar.

let a = true
b = false
if (!b) {
  a = false
}

Këtu ndryshorja b bëhet pjesë e objektit global dhe mbetet aty edhe pas ekzekutimit të funksionit tonë.
Zgjidhja:Thjesht sigurohuni që kjo të mos ndodhë, ekzekutimi i kodit në kod të rreptë do të parandalojë globale aksidentale. Nevojë e thjeshtë për të shtuar use strict; në fillim të skedarëve JavaScript.

Një tjetër shkak i zakonshëm i rrjedhjes së kujtesës në JavaScript është mbyllja. Mbylljet janë të pashmangshme dhe një pjesë integrale e JavaScript.
Si krijojnë mbylljet rrjedhje memorie? — Në përgjithësi variablat me shtrirje të funksionit do të lëshohen kur funksioni të ketë dalë nga grupi i thirrjeve. Por mbylljet do t'i mbajnë variablat gjallë edhe pasi konteksti i ekzekutimit dhe mjedisi i variablave janë zhdukur prej kohësh.
Parandalimi:Kuptimi i objekteve të ruajtura dhe jetëgjatësia e mbylljes do të ndihmojë. Rekomandohet kapërcimi i funksioneve të mbylljes me referenca funksionesh te funksionet e jashtme.

Përfundim
Në këtë artikull jam përpjekur të përmbledh disa koncepte thelbësore të menaxhimit të JavaScript dhe kujtesës