Event loop

졜근 μžλ°”μŠ€ν¬λ¦½νŠΈλΌλŠ” 언어에 λŒ€ν•΄μ„œ 곡뢀λ₯Ό ν•˜κ³  μžˆλŠ”λ° μ΄λ²ˆμ—λŠ” 이벀트 루프에 λŒ€ν•΄ 곡뢀해보렀 ν•œλ‹€.

μ‹œμž‘ν•˜κΈ° μ•žμ„œμ„œ

이벀트 λ£¨ν”„λŠ” λΈŒλΌμš°μ €μ™€ μžλ°”μŠ€ν¬λ¦½νŠΈ λŸ°νƒ€μž„ ν™˜κ²½ (Node js)μ—μ„œ μž‘μ—…μ„ μ‹€ν–‰ν• λ•Œ μ‚¬μš©λ˜λŠ” 메인 μŠ€λ ˆλ“œμ΄λ‹€. 보톡 "μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œ 언어이닀"라고듀 ν•˜λŠ”λ° κ·Έ μ΄μœ κ°€ λ°”λ‘œ λ©”μΈμŠ€λ ˆλ“œμΈ 이벀트 루프가 μ‹±κΈ€μŠ€λ ˆλ“œμ΄κΈ° λ•Œλ¬Έμ΄λ‹€.

그림을 λ³΄λ©΄μ„œ μ΄λ²€νŠΈλ£¨ν”„κ°€ μ–΄λ–»κ²Œ λ™μž‘ν•˜λŠ”μ§€ μ‚΄νŽ΄λ³΄μž

CallStack, Memory Heap

λ¨Όμ € κ·Έλ¦Ό μ™Όμͺ½μ— ν‘œμ‹œλœ μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진을 보자. λ©”λͺ¨λ¦¬ νž™μ΄λΌλŠ” 것과 μ½œμŠ€νƒμ΄λΌλŠ” κ²ƒμœΌλ‘œ 이루어져 μžˆλ‹€. λ©”λͺ¨λ¦¬νž™μ€ λ©”λͺ¨λ¦¬ 할당이 μΌμ–΄λ‚˜λŠ” 곳이고, μ½œμŠ€νƒμ€ 이름 κ·ΈλŒ€λ‘œ μ‹€ν–‰μ½”λ“œκ°€ ν•˜λ‚˜μ”© μŠ€νƒμ˜ ν˜•νƒœλ‘œ μŒ“μ΄λŠ” 곳이닀.

function multi(a, b) {
  return a * b;
}
function square(n) {
  return multi(n, n);
}
function printSquare(n) {
  let squared = square(n);
  console.log(squared);
}
printSquare(3);

μœ„μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ²Œ 되면 λ¨Όμ € λͺ¨λ“  μ½”λ“œλ₯Ό μ§€μΉ­ν•˜λŠ” λ©”μΈν•¨μˆ˜λ₯Ό μ½œμŠ€νƒμ— λ¨Όμ € λ„£κ²Œ λœλ‹€. κ·ΈλŸ¬λ‹€κ°€ κ°€μž₯ λ§ˆμ§€λ§‰μ€„μ— ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” printSquare(4)λ₯Ό λ§Œλ‚˜κ²Œ λ˜μ–΄ μ½œμŠ€νƒμ— μΆ”κ°€λœλ‹€. 이후 square, multiλ₯Ό μ°¨λ‘€λ‘œ ν˜ΈμΆœν•˜κ²Œ λ˜μ–΄ 콜 μŠ€νƒμ•ˆμ—λŠ” { main - printSquare - square - multi }의 순으둜 μŒ“μ΄κ²Œ λœλ‹€.(μŠ€νƒμ˜ ν˜•νƒœμ΄κΈ° λ•Œλ¬Έμ— 맨 μœ„μ— multiκ°€ μŒ“μ—¬μžˆλ‹€.) 이제 μŠ€νƒ 맨 μœ„μ— μžˆλŠ” ν•¨μˆ˜λΆ€ν„° return을 μ‹œν‚€λ©° ν•˜λ‚˜μ”© μŠ€νƒμ—μ„œ μ œκ±°ν•œλ‹€.


extra - Execution Context

사싀 μœ„μ˜ ν‘œν˜„μ—μ„œ ν•¨μˆ˜λ₯Ό μ½œμŠ€νƒμ— λ„£λŠ”λ‹€κ³  ν–ˆλŠ”λ° μ •ν™•νžˆ μ–˜κΈ°ν•˜λ©΄ ν•¨μˆ˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ (Execution Context)λ₯Ό μƒμ„±ν•˜κ³  μ½œμŠ€νƒμ— λ„£λŠ” 것이닀. λ§ˆμ°¬κ°€μ§€λ‘œ μ½œμŠ€νƒμ—μ„œ μ œκ±°λ λ•Œλ„ ν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ œκ±°λ˜λŠ” 것이닀.

μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ₯Ό μ—¬κΈ°μ„œ λ‹€ 닀루면 이벀트 루프λ₯Ό 주제둜 ν•˜λŠ” ν¬μŠ€νŒ…μ—μ„œ μ—‡λ‚˜κ°ˆκ²ƒκ°™μ•„ κ°„λ‹¨νžˆ μ„€λͺ… ν›„ λ‹€λ₯Έ ν¬μŠ€νŒ…μ—μ„œ 닀루렀고 ν•œλ‹€.

μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλŠ” κ°„λ‹¨νžˆ λ§ν•˜μžλ©΄ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ μ‹€ν–‰λ˜λŠ” μ˜μ—­μ΄λ‹€. 크게 3κ°€μ§€λ‘œ λΆ„λ¦¬λ˜λŠ”λ°

  • μ „μ—­μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ μ½”λ“œλ₯Ό μ‹€ν–‰ν• λ•Œ 졜초둜 μƒμ„±λ˜λŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ΄λ‹€. μ½”λ“œλ‚΄μš©μ΄ 없어도 전역객체인 window와 이λ₯Ό κ°€λ¦¬ν‚€λŠ” thisκ°€ μƒμ„±λœλ‹€. (λΈŒλΌμš°μ €μ—μ„œ console.log(this)λ₯Ό μ‹€ν–‰ν•˜λ©΄ Window 객체가 λ‚˜μ˜€λŠ” μ΄μœ κ°€ λ°”λ‘œ 이것이닀.)

  • ν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ 졜초 μ½”λ“œ μ‹€ν–‰ 이후 ν•¨μˆ˜κ°€ ν˜ΈμΆœλ λ•Œλ§ˆλ‹€ 각 ν•¨μˆ˜λ³„λ‘œ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ₯Ό μƒμ„±λœλ‹€. λ”°λΌμ„œ ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜μ§€ μ•ŠμœΌλ©΄ ν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλŠ” μƒμ„±λ˜μ§€ μ•ŠλŠ”λ‹€.

    ν—·κ°ˆλ¦¬λ©΄ μ•ˆλ˜λŠ” 점은 ν•¨μˆ˜ 선언이 μ•„λ‹ˆλΌ μ‹€ν–‰μ‹œμ— μƒμ„±λœλ‹€λŠ” 점이닀.

  • Evalμ‹€ν–‰ μ»¨ν…μŠ€νŠΈ


즉, μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν•˜λ‚˜μ˜Call Stack으둜 λ™μž‘ν•˜κΈ° λ•Œλ¬Έμ— μ‹±κΈ€μŠ€λ ˆλ“œ μ–Έμ–΄λΌλŠ” 것을 μ•Œμˆ˜ μžˆλ‹€.

그런데 μš°λ¦¬κ°€ μ‹€μ œλ‘œ λΈŒλΌμš°μ €/Node jsλ₯Ό μ‚¬μš©ν• λ•ŒλŠ” μ—¬λŸ¬κ°œμ˜ μŠ€λ ˆλ“œκ°€ μ‚¬μš©λ˜λŠ”λ° μ–΄λ–€μ‹μœΌλ‘œ μž‘λ™ν•˜λŠ”μ§€ μ‚΄νŽ΄λ³΄μž.

Event Loop

function hi() {
  return "hi!";
}
function respond() {
  return setTimeout(() => {
    return "Hello";
  }, 1000);
}

hi();
respond();

이전에 μ˜ˆμ‹œλ‘œ λ“€μ—ˆλ˜ μ½”λ“œμ™€ 달리 setTimeout ν•¨μˆ˜κ°€ λ“±μž₯ν•˜μ—¬ 비동기 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” μ½”λ“œμ΄λ‹€. μ‹€μ œλ‘œ λΈŒλΌμš°μ €μƒμ—μ„œλŠ” λΉ„λ™κΈ°λ‘œ μš”μ²­ν•˜λŠ” μž‘μ—…μ΄ μˆ˜μ—†μ΄ λ§Žλ‹€.

λ¨Όμ € μœ„ μ½”λ“œκ°€ μž‘λ™ν•˜λŠ” 과정을 μ‚΄νŽ΄λ³΄μž

  • hi ν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ™€ respondν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μˆœμ„œλŒ€λ‘œ μ½œμŠ€νƒμ— μŒ“μΈλ‹€.

  • ν•˜λ‹¨μ˜ μ‹€ν–‰κ΅¬λ¬ΈμœΌλ‘œ μΈν•˜μ—¬ hiν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ λ¨Όμ € μ½œμŠ€νƒμ—μ„œ μ œκ±°λœλ‹€.

  • λ‹€μŒμœΌλ‘œ respond ν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μ‹€ν–‰ ν›„ μ½œμŠ€νƒμ—μ„œ μ œκ±°λœλ‹€.

  • respond ν•¨μˆ˜ λ‚΄μ˜ setTimeoutμ΄λΌλŠ” WebApiκ°€ μ‘΄μž¬ν•˜λ―€λ‘œ λΈŒλΌμš°μ €κ°€ μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„κ³Ό λ‹€λ₯Έ μŠ€λ ˆλ“œμ—μ„œ ν•΄λ‹Ή μš”μ²­μ„ μ²˜λ¦¬ν•œλ‹€.

  • Web Apiμ—μ„œ setTimeout에 μ§€μ •λœ μ‹œκ°„μ΄ μ§€λ‚œ ν›„, μ „λ‹¬λœ μ½œλ°±ν•¨μˆ˜λŠ” Task Que 둜 μ „λ‹¬λœλ‹€. (μ½œμŠ€νƒμœΌλ‘œ μ „λ‹¬λ˜μ§€ μ•ŠλŠ”κ²ƒμ΄ 핡심이닀.)

  • 이후 λ§Œμ•½ μ½œμŠ€νƒμ΄ λΉ„μ–΄μžˆλ‹€λ©΄ ν•΄λ‹Ή ν•¨μˆ˜μ‹€ν–‰ μ»¨ν…μŠ€νŠΈλ₯Ό μ½œμŠ€νƒμœΌλ‘œ μ „λ‹¬ν•˜κ³  λΉ„μ–΄μžˆμ§€ μ•Šλ‹€λ©΄ μ „λ‹¬ν•˜μ§€ μ•ŠλŠ”λ‹€.

  • μ½œμŠ€νƒμ΄ λΉ„μ–΄μžˆμœΌλ―€λ‘œ ν•¨μˆ˜λ₯Ό μ½œμŠ€νƒμœΌλ‘œ μ „λ‹¬ν•œ ν›„ κ²°κ³Ό 좜λ ₯이후에 μ œκ±°λœλ‹€.

Web Api, Task Que같은 μƒˆλ‘œμš΄ κ°œλ…μ΄ λ“±μž₯ν–ˆμœΌλ‹ˆ λ¨Όμ € ν•΄λ‹Ή κ°œλ…μ— λŒ€ν•΄ κ³΅λΆ€ν•΄λ³΄μž


Web Api

μ˜ˆμ‹œμ—μ„œ λ‚˜μ˜¨ setTimeout을 ν¬ν•¨ν•˜μ—¬ Ajax , Event Listener 처럼 μ›ΉλΈŒλΌμš°μ €μ—μ„œ μ œκ³΅ν•˜λŠ” κΈ°λŠ₯듀을 μΌμ»«λŠ”λ‹€.

κ³Όμ • μ„€λͺ…을 톡해 μ–ΈκΈ‰ν•œ κ²ƒμ²˜λŸΌ μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ˜ μ½œμŠ€νƒμ—μ„œ 비동기 ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜λŠ” 경우, ν•΄λ‹Ή ν•¨μˆ˜κ°€ μš”μ²­ν•˜λŠ” 비동기 μž‘μ—…μ •λ³΄μ™€ μ½œλ°±ν•¨μˆ˜λ₯Ό Web Apiλ₯Ό ν†΅ν•˜μ—¬ λΈŒλΌμš°μ €μ—κ²Œ μ „λ‹¬ν•œλ‹€. 이후 λΈŒλΌμš°μ €λŠ” 전달받은 μš”μ²­λ“€μ„ λ³„λ„μ˜ μŠ€λ ˆλ“œμ— μœ„μž„ν•œ ν›„, μš”μ²­μ΄ μ™„λ£Œλ¨κ³Ό λ™μ‹œμ— Task Que에 μ „λ‹¬ν•œλ‹€.

Task Que

νƒœμŠ€ν¬νλŠ” μ›Ή api둜 λΆ€ν„° 전달받은 μ½œλ°±ν•¨μˆ˜λ“€μ„ 큐의 ν˜•νƒœλ‘œ μ €μž₯ν•œλ‹€. μ›Ή api와 달리 μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진에 ν¬ν•¨λ˜μ–΄ 있으며, μ €μž₯된 ν•¨μˆ˜λ“€μ€ μ½œμŠ€νƒμ΄ λΉ„λŠ” μˆœκ°„ μ°¨λ‘€λŒ€λ‘œ μ „λ‹¬λœλ‹€. μœ μ˜ν•  점은 μ½œμŠ€νƒμ΄ λΉ„μ–΄μžˆμ„λ•Œ μ „λ‹¬λ˜κΈ° λ•Œλ¬Έμ—, μ§€μ •(μ˜ˆμƒ)ν•œ μ‹œκ°„λ³΄λ‹€ 더 늦게 싀행될 μˆ˜λ„ μžˆλ‹€.


이제 λ‹€μ‹œ μ˜ˆμ‹œμ½”λ“œμ˜ λ™μž‘κ³Όμ •μ„ μ‚΄νŽ΄λ³΄μž.

μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ˜ Call Stackκ³Ό Task QueλŠ” λ‹¨μΌμŠ€λ ˆλ“œλ‘œ λ™μž‘ν•˜λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μž‘μ—…μ„ λ³„λ„μ˜ μŠ€λ ˆλ“œμ—μ„œ μž‘μ—…ν• μˆ˜ μžˆλ„λ‘ 도와쀀닀.

쑰금 더 생각해보면 μš°λ¦¬λŠ” μ½œμŠ€νƒμ΄ λΉ„μ–΄μžˆλŠ”μ§€, νƒœμŠ€ν¬νμ— ν•¨μˆ˜κ°€ μžˆλŠ”μ§€λ₯Ό μ§€μ†μ μœΌλ‘œ 확인을 ν•΄μ£Όμ–΄μ•Ό ν•  ν•„μš”μ„±μ΄ μžˆλ‹€. 확인을 μ§€μ†μ μœΌλ‘œ ν•΄μ£Όμ§€ μ•ŠλŠ”λ‹€λ©΄ νƒœμŠ€ν¬νμ— μžˆλŠ” ν•¨μˆ˜κ°€ μ½œμŠ€νƒμ΄ λΉ„μ–΄μžˆμŒμ—λ„ λΆˆκ΅¬ν•˜κ³  μ „λ‹¬λ˜μ§€ μ•Šμ•„ μ‹€ν–‰λ˜μ§€ μ•Šμ„μˆ˜ 있기 λ•Œλ¬Έμ΄λ‹€. μ‚¬μš©μž κ²½ν—˜μ„ 맀우 μ€‘μ‹œν•˜λŠ” λΈŒλΌμš°μ €μ—μ„œ μ΄λŸ¬ν•œ ν˜„μƒμ€ 치λͺ…적일 수 밖에 μ—†λ‹€.

이 역할을 μˆ˜ν–‰ν•΄ μ£ΌλŠ” 것이 λ°”λ‘œ Event Loop이닀. μ΄λ²€νŠΈλ£¨ν”„λŠ” μ½œμŠ€νƒκ³Ό νƒœμŠ€ν¬νλ₯Ό μ§€μ†μ μœΌλ‘œ 보고 μžˆλ‹€κ°€ μ½œμŠ€νƒμ΄ λΉ„μ›Œμ§€λŠ” μˆœκ°„ νƒœμŠ€ν¬νμ— μžˆλŠ” μ½œλ°±ν•¨μˆ˜λ₯Ό μ „λ‹¬μ‹œν‚€λŠ” 역할을 ν•œλ‹€.

전체적인 νλ¦„μ—μ„œμ˜ λ™μž‘μ„ λ‹€μ‹œ ν•œλ²ˆ μ‚΄νŽ΄λ³΄λ©΄

  • ν•¨μˆ˜1, ν•¨μˆ˜ 2(setTimeout)λ₯Ό Call Stack에 μ‚½μž…

  • ν•¨μˆ˜1을 μ‹€ν–‰ ν›„ 제거

  • ν•¨μˆ˜2에 setTimeout이 ν¬ν•¨λ˜μ–΄ μžˆμœΌλ―€λ‘œ μŠ€νƒμ—μ„œ μ œκ±°ν•˜κ³  Web Api둜 전달

  • Web Apiμ—μ„œ μ‹€ν–‰λœ κ²°κ³Όλ₯Ό Task Que둜 전달

  • Event LoopλŠ” Call Stack을 ν™•μΈν•˜κ³  λΉ„μ–΄μžˆμœΌλ―€λ‘œ Task Que ➑️ Call Stack으둜 ν•΄λ‹Ή ν•¨μˆ˜ 전달

  • μ‹€ν–‰ ν›„ 제거

μœ„μ™€ 같은 λ™μž‘κ³Όμ •μ„ κ±°μΉ˜λŠ” 것을 확인할 수 μžˆλ‹€.

정리

κ³΅λΆ€ν•œ λ‚΄μš©μ„ μ •λ¦¬ν•΄λ³΄μžλ©΄

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 단일 μ½œμŠ€νƒμ„ μ‚¬μš©ν•œλ‹€λŠ” μ μ—μ„œ μ‹±κΈ€ μŠ€λ ˆλ“œ 언어라고 ν• μˆ˜ μžˆλ‹€. ν•˜μ§€λ§Œ μ‹€μ œλ‘œ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ μ‚¬μš©λ˜λŠ” ν™˜κ²½μΈ λΈŒλΌμš°μ €λ‚˜ Node jsμ—μ„œλŠ” μ—¬λŸ¬κ°œμ˜ μŠ€λ ˆλ“œκ°€ μ‚¬μš©λ˜λŠ”λ°, λ‹€μˆ˜μ˜ μŠ€λ ˆλ“œ ν™˜κ²½κ³Ό 단일 μŠ€λ ˆλ“œ μ–Έμ–΄λ₯Ό μ—°λ™ν•˜κΈ° μœ„ν•΄μ„œ Event Loopκ°€ μ‚¬μš©λœλ‹€.

Last updated