/
πŸ“™

JS asynchronous

JavaScript
Table of contents

μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 비동기(asynchronous)

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” Single-Thread 기반

μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진이 λ™μž‘ν•˜λŠ” λΈŒλΌμš°μ € ν™˜κ²½μ΄λ‚˜ Node.js ν™˜κ²½μ€ ν•œλ²ˆμ— ν•˜λ‚˜μ˜ νƒœμŠ€ν¬(task)λ§Œμ„ μ‹€ν–‰ν•  수 μžˆλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œ(single thread) 이닀.

ν•œλ²ˆμ— ν•˜λ‚˜μ˜ νƒœμŠ€ν¬λ§Œ 처리

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” ν•¨μˆ˜μ˜ μ‹€ν–‰ μˆœμ„œλ₯Ό μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ μŠ€νƒμœΌλ‘œ κ΄€λ¦¬ν•˜κ³  μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진은 단 ν•˜λ‚˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ μŠ€νƒ 을 κ°–λŠ”λ‹€. λ•Œλ¬Έμ— ν•œλ²ˆμ— ν•˜λ‚˜μ˜ νƒœμŠ€ν¬λ§Œμ„ μ²˜λ¦¬ν•  수 있고, 이것을 콜 μŠ€νƒ 이라 λΆ€λ₯Έλ‹€.

one thread == one call stack == one thing at a time

ν•˜λ‚˜μ˜ νƒœμŠ€ν¬λ§Œμ„ μ‹€ν–‰ν•  수 있기 λ•Œλ¬Έμ— μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” νƒœμŠ€ν¬λ₯Ό μ‹€ν–‰ν•˜λ©΄ λΈ”λ‘œν‚Ήμ΄ λ°œμƒν•œλ‹€.
λΈ”λ‘œν‚Ήμ΄ λ°œμƒν•˜λ©΄ λΈŒλΌμš°μ € 화면이 λ©ˆμΆ”κ±°λ‚˜ λŠλ €μ§€λŠ”κ±Έ λ³Ό 수 μžˆλ‹€. μ΄λŠ” νƒœμŠ€ν¬λ₯Ό μ‹€ν–‰ν•˜λŠ” λ™μ•ˆ λžœλ”λ§μ΄ λΆˆκ°€λŠ₯ ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

콜 μŠ€νƒ(Call stack, μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ μŠ€νƒ)

μ†ŒμŠ€ μ½”λ“œ(μ „μ—­ μ½”λ“œλ‚˜ ν•¨μˆ˜ μ½”λ“œ λ“±) 평가에 μ˜ν•΄ μƒμ„±λœ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μΆ”κ°€(push)되고 제거(pop)λ˜λŠ” μŠ€νƒ 자료 ꡬ쑰

λΈ”λ‘œν‚Ή(Blocking, μž‘μ—… 쀑단)

μ½”λ“œ 싀행을 λŠλ¦¬κ±°λ‚˜ λ©ˆμΆ”κ²Œ λ§Œλ“œλŠ” 것.

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” λ™μ‹œμ„±μ„ μ§€μ›ν•œλ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œλ‘œ λ™μž‘ν•˜μ—¬ ν•œλ²ˆμ— ν•˜λ‚˜μ˜ νƒœμŠ€ν¬λ§Œ μ²˜λ¦¬ν•  수 μžˆλŠ” 동기식 처리 λͺ¨λΈ μ΄μ§€λ§Œ 이벀트 루프(Event Loop) 와 νƒœμŠ€ν¬ 큐(Task Queues) λ₯Ό μ΄μš©ν•΄ λ™μ‹œμ„±(Concurrency) 을 μ§€μ›ν•˜μ—¬ μ‹±κΈ€ μŠ€λ ˆλ“œμ˜ 단점을 보완해 μ€€λ‹€.

동기식 처리 λͺ¨λΈ(Synchronous processing model)

싀행쀑인 νƒœμŠ€ν¬κ°€ μ’…λ£Œλ  λ•Œκ°€μ§€ λ‹€μŒ 싀행될 νƒœμŠ€ν¬κ°€ λŒ€κΈ°ν•˜λŠ” 방식

비동기식 처리 λͺ¨λΈ(Asynchronous processing model)

ν˜„μž¬ 싀행쀑인 νƒœμŠ€ν¬κ°€ μ’…λ£Œλ˜μ§€ μ•Šμ€ μƒνƒœλΌ ν•˜λ”λΌλ„ λ‹€μŒ νƒœμŠ€ν¬λ₯Ό κ³§λ°”λ‘œ μ‹€ν–‰ν•˜λŠ” 방식

비동기 ν”„λ‘œκ·Έλž˜λ°

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œμ˜ 단점을 κ·Ήλ³΅ν•˜κΈ° μœ„ν•΄ 비동기 ν”„λ‘œκ·Έλž˜λ°μ„ μ‚¬μš©ν•˜κ³  비동기 μš”μ²­ μ²˜λ¦¬λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진을 κ΅¬λ™ν•˜λŠ” ν™˜κ²½μ΄ λ‹΄λ‹Ή ν•œλ‹€.

μ‹€μ œ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ κ΅¬λ™λ˜λŠ” ν™˜κ²½(λΈŒλΌμš°μ €, Node.jsλ“±)μ—μ„œλŠ” 주둜 μ—¬λŸ¬ 개의 μŠ€λ ˆλ“œκ°€ μ‚¬μš©λ˜λ©°, μ΄λŸ¬ν•œ ꡬ동 ν™˜κ²½μ΄ 단일 호좜 μŠ€νƒμ„ μ‚¬μš©ν•˜λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진과 μƒν˜Έ μ—°λ™ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•˜λŠ” μž₯μΉ˜κ°€ λ°”λ‘œ '이벀트 루프' 인 것이닀.

μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” νƒœμŠ€ν¬λŠ” λ‹€λ₯Έ μŠ€λ ˆλ“œ(WebAPI, Node API)에 μœ„μž„ν•˜κ³  λ…Ό λΈ”λ‘œν‚ΉμœΌλ‘œ νƒœμŠ€ν¬λ₯Ό μ²˜λ¦¬ν•œλ‹€. μœ„μž„ 받은 μŠ€λ ˆλ“œμ—μ„œ νƒœμŠ€ν¬κ°€ μ™„λ£Œλ˜λ©΄ 콜백 ν•¨μˆ˜λ₯Ό Task Queue에 μΆ”κ°€ ν•œλ‹€.

λ…Ό λΈ”λ‘œν‚Ή(Non-Blocking)

λ‹€λ₯Έ μŠ€λ ˆλ“œμ— μœ„μž„ν•œ νƒœμŠ€ν¬λ₯Ό 기닀리지 μ•Šκ³  λ°”λ‘œ λ‹€μŒ νƒœμŠ€ν¬λ₯Ό μ²˜λ¦¬ν•˜λŠ” 것.

Event Loop

콜 μŠ€νƒμ— ν˜„μž¬ 싀행쀑인 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ μžˆλŠ”μ§€ 그리고 νƒœμŠ€ν¬ 큐에 λŒ€κΈ° 쀑인 ν•¨μˆ˜(콜백 ν•¨μˆ˜, 이벀트 ν•Έλ“€λŸ¬ λ“±)κ°€ μžˆλŠ”μ§€ λ°˜λ³΅ν•˜μ—¬ ν™•μΈν•œλ‹€.

콜 μŠ€νƒμ΄ λΉ„μ–΄μžˆλ‹€λ©΄ νƒœμŠ€ν¬ νμ—μ„œ λŒ€κΈ° 쀑인 ν•¨μˆ˜λ₯Ό 순차적(FIFO)으둜 콜 μŠ€νƒμœΌλ‘œ μ΄λ™μ‹œν‚¨λ‹€.

(μ΄λ•Œ νƒœμŠ€ν¬ 큐에 μžˆλŠ” ν•¨μˆ˜λ“€μ΄ 콜 μŠ€νƒμ— λ“€μ–΄κ°ˆ ν‹ˆμ„ 잘 λ§Œλ“€μ–΄ μ£ΌλŠ” 것이 μžλ°”μŠ€ν¬λ¦½νŠΈ 비동기 ν”„λ‘œκ·Έλž˜λ°μ—μ„œ μ€‘μš”ν•œ 점인 것 κ°™λ‹€)

Task Queue(Event queue/Callback queue)

νƒœμŠ€ν¬ νλŠ” 비동기 처리 ν•¨μˆ˜μ˜ 콜백 ν•¨μˆ˜ λ˜λŠ” 이벀트 ν•Έλ“€λŸ¬κ°€ μΌμ‹œμ μœΌλ‘œ λ³΄κ΄€λ˜λŠ” μ˜μ—­μ΄λ‹€.
이곳에 μž„μ‹œ λ³΄κ΄€λœ ν•¨μˆ˜λ“€μ€ 비동기 처리 λͺ¨λΈλ‘œ λ™μž‘ν•œλ‹€.

λŒ€κΈ° 쀑인 ν•¨μˆ˜λŠ” 콜 μŠ€νƒμ΄ λΉ„μ–΄μ‘Œμ„ λ•Œ Event loop에 μ˜ν•΄ FIFO둜 콜 μŠ€νƒμœΌλ‘œ μ΄λ™λ˜μ–΄ μ‹€ν–‰λœλ‹€.

예제

λΈŒλΌμš°μ €μ—μ„œ 이벀트 루프가 μ–΄λ–»κ²Œ λ™μž‘ν•˜λŠ”μ§€ 그림으둜 잘 λ³΄μ—¬μ£ΌλŠ” 예제

javascript
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");
bar();
foo();
baz();
Visualized Event Loop

좜처: βœ¨β™»οΈ JavaScript Visualized: Event Loop

μœ„ μ™€λŠ” λ‹€λ₯΄μ§€λ§Œ http://latentflip.com/loupe에 λ“€μ–΄κ°€ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ event loopκ°€ λ™μž‘ν•˜λŠ” λͺ¨μŠ΅μ„ μ‹œκ°ν™” ν•΄μ€€λ‹€.

μš”μ•½

  • μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œμ΄λ‹€.
  • μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진은 단 ν•˜λ‚˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ μŠ€νƒμ„ κ°–λŠ”λ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œμ΄κ³  ν•˜λ‚˜μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ ν™˜κ²½μ„ κ°–κ³  있으며, 싀행쀑인 νƒœμŠ€ν¬κ°€ μ’…λ£Œλ  λ•Œκ°€μ§€ λ‹€μŒ 싀행될 νƒœμŠ€ν¬κ°€ λŒ€κΈ°ν•˜λŠ” 동기식 처리 λͺ¨λΈμ΄λ‹€.

  • 비동기 μš”μ²­ μ²˜λ¦¬λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진을 κ΅¬λ™ν•˜λŠ” ν™˜κ²½μΈ λΈŒλΌμš°μ €λ‚˜ Node.jsκ°€ λ‹΄λ‹Ήν•œλ‹€.
  • 이벀트 루프와 νƒœμŠ€ν¬ 큐λ₯Ό μ΄μš©ν•΄ λ™μ‹œμ„±μ„ μ§€μ›ν•œλ‹€.

비동기 μš”μ²­ μ²˜λ¦¬λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진을 κ΅¬λ™ν•˜λŠ” ν™˜κ²½μ΄ λ‹΄λ‹Ήν•˜λ©°, 이벀트 루프λ₯Ό μ΄μš©ν•΄ 단일 콜 μŠ€νƒκ³Ό μƒν˜Έ μ—°λ™λœλ‹€.

  • λͺ¨λ“  비동기 API듀은 μž‘μ—…μ΄ μ™„λ£Œλ˜λ©΄ 콜백 ν•¨μˆ˜λ₯Ό νƒœμŠ€ν¬ 큐에 μΆ”κ°€ν•œλ‹€.
  • 이벀트 λ£¨ν”„λŠ” 'ν˜„μž¬ 싀행쀑인 νƒœμŠ€ν¬κ°€ 없을 λ•Œ'(주둜 콜 μŠ€νƒμ΄ λΉ„μ›Œμ‘Œμ„ λ•Œ) νƒœμŠ€ν¬ 큐의 첫 번째 νƒœμŠ€ν¬λ₯Ό 꺼내와 μ‹€ν–‰ν•œλ‹€.

비동기 μž‘μ—…μ΄ μ™„λ£Œλ˜λ©΄ 콜백 ν•¨μˆ˜λ₯Ό νƒœμŠ€ν¬ 큐에 μΆ”κ°€ν•˜κ³  이벀트 λ£¨ν”„λŠ” 콜 μŠ€νƒμ΄ λΉ„μ›Œμ Έ μžˆμ„ λ•Œ νƒœμŠ€ν¬ νμ—μ„œ 첫 번째 νƒœμŠ€ν¬λ₯Ό 콜 μŠ€νƒμœΌλ‘œ μ΄λ™μ‹œν‚€κ³  콜 μŠ€νƒμ€ 이것을 μ‹€ν–‰ν•œλ‹€.

ν•œ 쀄 μš”μ•½

'μ‹±κΈ€ μŠ€λ ˆλ“œ 기반 μ΄μ§€λ§Œ 비동기 μ²˜λ¦¬κ°€ κ°€λŠ₯ν•˜λ‹€'

reference

What the heck is the event loop anyway? (이 μ˜μƒλΆ€ν„° 보면 μ΄ν•΄ν•˜κΈ°κ°€ 더 쉽닀)

Event | PoiemaWeb

μžλ°”μŠ€ν¬λ¦½νŠΈμ™€ 이벀트 루프

βœ¨β™»οΈ JavaScript Visualized: Event Loop

JS λΉ„λ™κΈ°λŠ” μ–΄λ–»κ²Œ κ΅¬ν˜„λ˜μ–΄μžˆλŠ”κ°€??

logo
Things I've Learned