Event Loop

JavaScript๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์–ธ์–ด์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด๋‚˜ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๊ฐ™์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์—…๋“ค์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ๋Š” JavaScript๊ฐ€ ์ด๋Ÿฌํ•œ ๋™์‹œ์„ฑ์„ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์ด์šฉํ•ด ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค.

Call Stack

RangeError: Maximum call stack size exceeded

JavaScript์—์„œ ๋ฌดํ•œ ์žฌ๊ท€ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ, ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋ณธ ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์„œ ์–ธ๊ธ‰๋œ 'call stack'์€, JavaScript ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ์Šคํƒ ๊ตฌ์กฐ์ด๋‹ค. 'stack' ์ด๋ผ๋Š” ๋„ค์ด๋ฐ์— ๊ฑธ๋งž๊ฒŒ LIFO(Last In First Out) ๋ฐฉ์‹์ด๋‹ค.

JavaScript๋Š” ํ•˜๋‚˜์˜ call stack๋งŒ์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ˜„์žฌ stack์— ์ถ”๊ฐ€๋œ ๋ชจ๋“  ํ•จ์ˆ˜๋“ค์ด ์‹คํ–‰๋  ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋ฏธ์ง€ ํ”„๋กœ์„ธ์‹ฑ, ๋„คํŠธ์›Œํฌ ์š”์ฒญ ๋“ฑ์˜ ๋ฌด๊ฑฐ์šด ์ž‘์—…๋“ค์ด call stack์— ์ถ”๊ฐ€๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ๋‹ค๋ฅธ ํ•จ์ˆ˜๋“ค์€ '๋ธ”๋กœํ‚น'๋œ ์ƒํƒœ๋กœ ๋ฌด๊ฑฐ์šด ์ž‘์—…์ด ๋๋‚˜๊ธฐ ์ „๊นŒ์ง€ ์‹คํ–‰๋˜์ง€ ๋ชปํ•  ๊ฒƒ์ด๋‹ค.

Callback Queue

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ JavaScript์—์„œ๋Š” ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค. ์ด ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์ด ์Œ“์ด๋Š” ๊ณณ์ด callback queue๋กœ, task queue, microtask queue, animation frame ๋“ฑ์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค. callback queue๋Š” FIFO(First In First Out) ๋ฐฉ์‹์œผ๋กœ, ๋จผ์ € ์ถ”๊ฐ€๋œ ์ฝœ๋ฐฑ์ด ๋จผ์ € ์ œ๊ฑฐ๋œ๋‹ค.

์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž.

function a() {
    setTimeout(() => console.log('setTimeout a'), 1000);
}

function b() {
    console.log('b');
}

a();
b();

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด console์— 'b'๊ฐ€ ๋จผ์ € ์ถœ๋ ฅ๋˜๊ณ  'setTimeout a'๊ฐ€ ๋‚˜์ค‘์— ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์— ๋‹จ๊ณ„๋ณ„๋กœ call stack๊ณผ callback queue์—์„œ ์–ด๋–ค ์ผ๋“ค์ด ๋ฐœ์ƒํ•˜๊ณ  ์žˆ๋Š”์ง€ ์„ค๋ช…ํ•œ๋‹ค.

  1. call stack์— a๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

  2. call stack์— a ๋‚ด๋ถ€์˜ setTimeout ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

  3. setTimeout์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๊ณตํ•˜๋Š” Web API์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ธŒ๋ผ์šฐ์ €์—์„œ ํƒ€์ด๋จธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

  4. (ํƒ€์ด๋จธ์˜ ์™„๋ฃŒ์™€๋Š” ๋ฌด๊ด€ํ•˜๊ฒŒ) call stack์—์„œ setTimeout ํ•จ์ˆ˜๊ฐ€ ์ œ๊ฑฐ๋œ๋‹ค.

  5. call stack์—์„œ a๊ฐ€ ์ œ๊ฑฐ๋œ๋‹ค.

  6. call stack์— b๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

  7. call stack์— b ๋‚ด๋ถ€์˜ console.log('b') ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

  8. b ๋‚ด๋ถ€์˜ console.log('b')๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

  9. call stack์—์„œ console.log('b'), b๊ฐ€ ์ œ๊ฑฐ๋œ๋‹ค.

  10. ํƒ€์ด๋จธ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ setTimeout์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ callback queue์— ์ถ”๊ฐ€ํ•œ๋‹ค.

  11. call stack์ด ๋น„์–ด์žˆ์œผ๋ฉด, callback queue์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜(console.log('setTimeout a'))๋ฅผ call stack์— ์ถ”๊ฐ€ํ•œ๋‹ค. (callback queue์—์„œ๋Š” ์ œ๊ฑฐํ•œ๋‹ค.)

  12. console.log('setTimeout a')๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

  13. call stack์—์„œ console.log('setTimeout a')๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.

4๋ฒˆ์—์„œ ๋งํ–ˆ๋“ฏ, callback queue๋กœ ์ด๋™๋  ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์€ ๋‹ค๋ฅธ JavaScript ํ•จ์ˆ˜์˜ ์‹คํ–‰์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

์˜๋ฌธ์ ์ด ๋“œ๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค. 11๋ฒˆ์—์„œ call stack์ด ๋น„์–ด์žˆ์œผ๋ฉด, callback queue์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ call stack์— ์ถ”๊ฐ€ํ•˜๋Š” ๋™์ž‘์€ ๋ˆ„๊ฐ€ ๋‹ด๋‹นํ•˜๋Š” ๊ฒƒ์ผ๊นŒ?

Event Loop

์ •๋‹ต์€ ์ด ๊ธ€์˜ ์ฃผ์ œ์ธ ์ด๋ฒคํŠธ ๋ฃจํ”„์ด๋‹ค. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” "call stack์ด ๋น„๋ฉด callback queue์—์„œ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ call stack์— ์ถ”๊ฐ€ํ•œ๋‹ค." ๋ผ๋Š” ๋งค์šฐ ๋‹จ์ˆœํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค. (๋น„์ฃผ์–ผ ์˜ˆ์‹œ) ํ•˜์ง€๋งŒ ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ, callback queue์—๋Š” ๋‹ค์–‘ํ•œ queue๋“ค์ด ์กด์žฌํ•˜๊ณ  ์ด๋“ค์€ ๊ฐ๊ฐ์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ด ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š”๋ฐ, ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. microtask queue(ex. Promise)

  2. animation frame(ex. requestAnimationFrame)

  3. task queue(ex. setTimeout, fetch)

setTimeout(() => {
    console.log('task queue');
}, 0);

Promise.resolve().then(() => {
    console.log('microtask queue');
});

requestAnimationFrame(() => {
    console.log('animation frame');
});

์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, console์— 'microtask queue' -> 'animation frame' -> 'task queue' ์ˆœ์œผ๋กœ ์ถœ๋ ฅ๋œ๋‹ค.

๋ฒˆ์™ธ: setTimeout์˜ ๋น„๋ฐ€

setTimeout(callback, 0)์€ 0์ดˆ ๋’ค ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์‹คํ–‰์„ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. call stack์ด ๋น„์–ด ์žˆ์–ด์•ผ์ง€๋งŒ call stack์— ๋“ฑ๋ก๋  ์ˆ˜ ์žˆ๋‹ค: ์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋“ฏ์ด, ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋” ๋†’์€ ์ž‘์—…๋“ค์ด ๋จผ์ € ์‹คํ–‰๋œ๋‹ค.

  2. (๋ธŒ๋ผ์šฐ์ €์˜ ๊ฒฝ์šฐ) 5๋ฒˆ์งธ ์ค‘์ฒฉ ํƒ€์ด๋จธ ์‹คํ–‰ ์‹œ, ํƒ€์ด๋จธ์˜ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด 4ms ์ด์ƒ์œผ๋กœ ๊ฐ•์ œ๋œ๋‹ค: HTML ํ‘œ์ค€์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค.

ํ™œ์šฉํ•˜๊ธฐ

๋™๊ธฐ์ ์ธ ์ž‘์—… ๋˜๋Š” DOM ๋ Œ๋”๋ง ์ดํ›„์— ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ setTimeout(callback, 0)์„ ์ด์šฉํ•ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

setTimeout(() => {
  animation(); // render ์ดํ›„์— ์‹คํ–‰๋œ๋‹ค.
}, 0);

render();

์ฐธ๊ณ  ๋ฌธ์„œ

Last updated