๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

[Medium] ๐Ÿ“„ Event Loop

1. Why Javascript need asynchronous ? And please explain callback and event loopโ€‹

JavaScript์— ๋น„๋™๊ธฐ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๋Š”? ๊ทธ๋ฆฌ๊ณ  callback๊ณผ event loop๋ฅผ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”

JavaScript๋Š” ๋ณธ์งˆ์ ์œผ๋กœ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์˜ DOM ๊ตฌ์กฐ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์ด ์ฃผ์š” ์—ญํ•  ์ค‘ ํ•˜๋‚˜์ธ๋ฐ, ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋กœ ๊ฐ™์€ ๋…ธ๋“œ๋ฅผ ๋™์‹œ์— ์ˆ˜์ •ํ•˜๋ฉด ์ƒํ™ฉ์ด ๋งค์šฐ ๋ณต์žกํ•ด์ง€๋ฏ€๋กœ ์ด๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋ฅผ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋ผ๋Š” ๋ฐฐ๊ฒฝ์—์„œ์˜ ํ•ด๊ฒฐ์ฑ…์ž…๋‹ˆ๋‹ค. ํŠน์ • ๋™์ž‘์ด 2์ดˆ์˜ ๋Œ€๊ธฐ๊ฐ€ ํ•„์š”ํ•  ๋•Œ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ 2์ดˆ๋ฅผ ๊ธฐ๋‹ค๋ฆด ์ˆ˜๋Š” ์—†์œผ๋ฏ€๋กœ ๋ชจ๋“  ๋™๊ธฐ ์ž‘์—…์„ ๋จผ์ € ์‹คํ–‰ํ•˜๊ณ , ๋น„๋™๊ธฐ ์ž‘์—…์€ task queue(์ž‘์—… ๋Œ€๊ธฐ์—ด)์— ๋„ฃ์–ด๋‘ก๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋™๊ธฐ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋Š” ํ™˜๊ฒฝ์€ call stack์œผ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ๋จผ์ € call stack ๋‚ด์˜ ์ž‘์—…์„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•˜๊ณ , call stack์ด ๋น„์–ด์žˆ์Œ์„ ๊ฐ์ง€ํ•˜๋ฉด task queue์—์„œ ๋Œ€๊ธฐ ์ค‘์ธ ์ž‘์—…์„ call stack์œผ๋กœ ์˜ฎ๊ฒจ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  1. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ call stack์ด ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธ => ์•„๋‹ˆ์˜ค => call stack ๋‚ด ์ž‘์—… ๊ณ„์† ์‹คํ–‰
  2. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ call stack์ด ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธ => ์˜ˆ => task queue์— ๋Œ€๊ธฐ ์ค‘์ธ ์ž‘์—…์ด ์žˆ๋Š”์ง€ ํ™•์ธ => ์žˆ์Œ => call stack์œผ๋กœ ์˜ฎ๊ฒจ ์‹คํ–‰

์ด๋ ‡๊ฒŒ ๋Š์ž„์—†์ด ๋ฐ˜๋ณต๋˜๋Š” ๊ณผ์ •์ด event loop์˜ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.

console.log(1);

// ์ด ๋น„๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ callback์ž…๋‹ˆ๋‹ค
setTimeout(function () {
console.log(2);
}, 0);

console.log(3);

// ์ˆœ์„œ๋Œ€๋กœ 1 3 2๊ฐ€ ์ถœ๋ ฅ๋จ

2. Why is setInterval not accurate in terms of timing ?โ€‹

์™œ setInterval์˜ ํƒ€์ด๋ฐ์€ ์ •ํ™•ํ•˜์ง€ ์•Š์€๊ฐ€?

  1. JavaScript๊ฐ€ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ด๋ฏ€๋กœ(ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์‹คํ–‰ ๊ฐ€๋Šฅ, ๋‹ค๋ฅธ ์ž‘์—…์€ Queue์—์„œ ๋Œ€๊ธฐ), setInterval์˜ callback ์‹คํ–‰ ์‹œ๊ฐ„์ด ์„ค์ •๋œ ๊ฐ„๊ฒฉ์„ ์ดˆ๊ณผํ•˜๋ฉด ๋‹ค์Œ callback ์‹คํ–‰์ด ์ง€์—ฐ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 1์ดˆ๋งˆ๋‹ค ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ์„ค์ •ํ–ˆ์ง€๋งŒ ํ•จ์ˆ˜ ๋‚ด์— 2์ดˆ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด ๋‹ค์Œ ์‹คํ–‰์€ 1์ดˆ ์ง€์—ฐ๋ฉ๋‹ˆ๋‹ค. ๋ˆ„์ ๋˜๋ฉด ์‹คํ–‰ ํƒ€์ด๋ฐ์ด ์ ์  ๋ถ€์ •ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค.

  2. ๋ธŒ๋ผ์šฐ์ €๋‚˜ ์‹คํ–‰ ํ™˜๊ฒฝ์˜ ์ œํ•œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ €(Chrome, Firefox, Safari ๋“ฑ)์˜ ์ตœ์†Œ ๊ฐ„๊ฒฉ ์‹œ๊ฐ„์€ ๋Œ€๋žต 4๋ฐ€๋ฆฌ์ดˆ์ž…๋‹ˆ๋‹ค. 1๋ฐ€๋ฆฌ์ดˆ๋งˆ๋‹ค ์‹คํ–‰ํ•˜๋„๋ก ์„ค์ •ํ•ด๋„ ์‹ค์ œ๋กœ๋Š” 4๋ฐ€๋ฆฌ์ดˆ๋งˆ๋‹ค ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

  3. ์‹œ์Šคํ…œ์ด ๋ฉ”๋ชจ๋ฆฌ๋‚˜ CPU๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์ž‘์—…์„ ์‹คํ–‰ํ•  ๋•Œ๋„ ์‹คํ–‰ ์‹œ๊ฐ„ ์ง€์—ฐ์„ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค. ์˜์ƒ ํŽธ์ง‘์ด๋‚˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๊ฐ™์€ ์ž‘์—… ์‹œ ์ง€์—ฐ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค.

  4. JavaScript์—๋Š” Garbage Collection ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์žˆ์–ด, setInterval ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋Œ€๋Ÿ‰์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด GC์— ์˜ํ•ด ํšŒ์ˆ˜๋ฉ๋‹ˆ๋‹ค. ์ด ๋˜ํ•œ ์‹คํ–‰ ์‹œ๊ฐ„ ์ง€์—ฐ์˜ ์›์ธ์ด ๋ฉ๋‹ˆ๋‹ค.

๋Œ€์•ˆโ€‹

requestAnimationFrameโ€‹

ํ˜„์žฌ setInterval์„ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ตฌํ˜„ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, requestAnimationFrame์œผ๋กœ ๋Œ€์ฒด๋ฅผ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ธŒ๋ผ์šฐ์ € ๋ฆฌํŽ˜์ธํŠธ์™€ ๋™๊ธฐํ™”: ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ƒˆ ํ”„๋ ˆ์ž„์„ ๊ทธ๋ฆด ์ค€๋น„๊ฐ€ ๋˜์—ˆ์„ ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. setInterval์ด๋‚˜ setTimeout์œผ๋กœ ํƒ€์ด๋ฐ์„ ์ถ”์ธกํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค.
  • ์„ฑ๋Šฅ: ๋ธŒ๋ผ์šฐ์ € ๋ฆฌํŽ˜์ธํŠธ์™€ ๋™๊ธฐํ™”๋˜๋ฏ€๋กœ ๋ฆฌํŽ˜์ธํŠธ๊ฐ€ ํ•„์š” ์—†์„ ๋•Œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํƒญ์ด ๋น„ํ™œ์„ฑํ™”๋˜๊ฑฐ๋‚˜ ์ตœ์†Œํ™”๋  ๋•Œ ํŠนํžˆ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.
  • ์ž๋™ ์Šค๋กœํ‹€๋ง: ์žฅ์น˜์™€ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์‹คํ–‰ ๋นˆ๋„๋ฅผ ์ž๋™ ์กฐ์ ˆํ•˜๋ฉฐ, ๋ณดํ†ต ์ดˆ๋‹น 60ํ”„๋ ˆ์ž„์ž…๋‹ˆ๋‹ค.
  • ๊ณ ์ •๋ฐ€ ์‹œ๊ฐ„ ๋งค๊ฐœ๋ณ€์ˆ˜: DOMHighResTimeStamp ํƒ€์ž…์˜ ๋งˆ์ดํฌ๋กœ์ดˆ ์ •๋ฐ€๋„ ์‹œ๊ฐ„ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด, ์‹œ๊ฐ„์— ๋ฏผ๊ฐํ•œ ์ž‘์—…์„ ๋” ์ •ํ™•ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Exampleโ€‹
let startPos = 0;

function moveElement(timestamp) {
// update DOM position
startPos += 5;
document.getElementById(
'myElement'
).style.transform = `translateX(${startPos}px)`;

// ์š”์†Œ๊ฐ€ ์•„์ง ๋ชฉ์ ์ง€์— ๋„๋‹ฌํ•˜์ง€ ์•Š์•˜์œผ๋ฉด, ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ณ„์†
if (startPos < 500) {
requestAnimationFrame(moveElement);
}
}

// start the animation
requestAnimationFrame(moveElement);

moveElement()์€ ๊ฐ ํ”„๋ ˆ์ž„(๋ณดํ†ต ์ดˆ๋‹น 60ํ”„๋ ˆ์ž„)๋งˆ๋‹ค ์š”์†Œ์˜ ์œ„์น˜๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ 500 pixel์— ๋„๋‹ฌํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ setInterval๋ณด๋‹ค ๋” ๋ถ€๋“œ๋Ÿฝ๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.