[JS] Microtask Queue..? rAF..? ๐Ÿค”

xoxristineยท2024๋…„ 5์›” 7์ผ
0

์•„์ง ์ž‘์„ฑ ์ค‘์ธ ๋ฏธํกํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.. ๋น ๋ฅธ ์‹œ์ผ ๋‚ด์— ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿซ 

requestAnimationFrame()์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด...
Event Loop, Task Queue, Micro Task Queue ์—์„œ ๋” ๋‚˜์•„๊ฐ€ rAF๊นŒ์ง€ ์•Œ์•„๋ณด์ž.

๋จผ์ € ์ด ์ฝ”๋“œ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋งž์ถฐ๋ณด์ž

console.log("script start");
setTimeout(function() {
  console.log("setTimeout");
}, 0);
Promise.resolve().then(function() {
  console.log("promise1");
}).then(function() {
  console.log("promise2");
});
requestAnimationFrame(function {
    console.log("requestAnimationFrame");
})
console.log("script end");

์‹คํ–‰ ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ๋งž์ถ”์ง€ ๋ชปํ–ˆ๋‹ค๋ฉด ์•„๋ž˜ ๊ธ€์„ ์ฝ์–ด๋ณด๋ฉด์„œ ์•Œ์•„๋ณด์ž.

script start
script end
promise1
promise2
requestAnimationFrame
setTimeout

๐Ÿชก JS๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜ & ๋น„๋™๊ธฐ๋กœ ๋™์ž‘?

๐Ÿ“Œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ!

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜ ์–ธ์–ด๋กœ, ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์ด๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ํ™˜๊ฒฝ์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ์ด ์•„๋‹Œ ๋” ๋งŽ์€ ์ž‘์—…๋“ค์ด ๋™์‹œ์— ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ex) ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋ฉด์„œ ๋™์‹œ์— ๋งˆ์šฐ์Šค ์ž…๋ ฅ์„ ๋ฐ›์•„ ์ฒ˜๋ฆฌ
  • ex) Node.js ๊ธฐ๋ฐ˜์˜ ์›น์„œ๋ฒ„์—์„œ๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ HTTP ์š”์ฒญ์„ ์ฒ˜๋ฆฌ

๋‹จ์ผ ์Šค๋ ˆ๋“œ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋„ ๋™์‹œ์„ฑ์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๊ฒฐ์—๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์กด์žฌํ•˜์—ฌ ๋น„๋™๊ธฐ์ ์ธ ์ผ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ€๋Šฅ์ผ€ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐Ÿ“Œ ๊ทธ๋Ÿผ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ๋ˆ„๊ฐ€ ๋‹ด๋‹นํ•˜๋‚˜์š”?

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์ทจ๊ธ‰ X
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์—”์ง„์ธ V8์˜ ๊ฒฝ์šฐ Call stack์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ์š”์ฒญ์„ ์ˆœ์ฐจ์ ์œผ๋กœ stack์— ๋‹ด์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ผ ์ˆ˜ํ–‰

๋น„๋™๊ธฐ ์š”์ฒญ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์„ ๊ตฌ๋™ํ•˜๋Š” ํ™˜๊ฒฝ,
์ฆ‰ ๋ธŒ๋ผ์šฐ์ €๋‚˜ NodeJS๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค.

์•„๋ž˜ ์‚ฌ์ง„์—์„œ ๊ทธ ํ™˜๊ฒฝ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝWeb API
  • ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” setTimeout ์ด๋‚˜ XMLHttpRequest์™€ ๊ฐ™์€ ํ•จ์ˆ˜๋“ค์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด ์•„๋‹Œ Web API ์˜์—ญ์— ๋”ฐ๋กœ ์ •์˜
  • ์ด๋ฒคํŠธ ๋ฃจํ”„์™€ ํƒœ์Šคํฌ ํ์™€ ๊ฐ™์€ ์žฅ์น˜๋“ค๋„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„ ๋ฐ–์— ๊ตฌํ˜„

๐Ÿ“ Event Loop & Task Queue

  • ๋™๊ธฐ์ ์ธ Task: Call stack ์— ์˜ํ•˜์—ฌ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ
  • ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ: Web API์™€ Task Queue๋ฅผ ๊ฑฐ์นœ ๋’ค Call stack ์ด ๋น„์–ด์žˆ์„๋•Œ์—๋งŒ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์˜ํ•ด Call stack ์œผ๋กœ ์˜ฎ๊ฒจ์ ธ ์ฒ˜๋ฆฌ๋จ
    ex) setTimeout

๐Ÿ“ Task Queue & Microtask Queue

๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” Task๋Š” ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜๋กœ ๋‚˜๋‰˜๊ฒŒ ๋œ๋‹ค.

  1. Task Queue: setTimeout(), setInterval(), setImmediate() ๋“ฑ
  2. Microtask Queue: Promise์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜, async/await, process.nextTick, Object.observe, MutationObserver ๋“ฑ

์šฐ์„  ์ˆœ์œ„๋Š” Microtask Queue > Task Queue

Call stack์—์„œ ๋” ์ด์ƒ ์ฒ˜๋ฆฌํ•  task๊ฐ€ ์—†์„ ๋•Œ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋” ๋†’์€ Microtask Queue์— ์žˆ๋Š” ๋น„๋™๊ธฐ task๊ฐ€ ๋จผ์ € ์ฒ˜๋ฆฌ๋œ ์ดํ›„์—, Task Queue์— ์žˆ๋Š” task๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

์ฝ”๋“œ ์˜ˆ์‹œ์™€ ๊ทธ ์‹คํ–‰ ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

console.log('Start!');

setTimeout(() => {
	console.log('Timeout!');
}, 0);

Promise.resolve('Promise!').then(res => console.log(res));

console.log('End!');

๐Ÿ“ rAF? Animation Frames?

  • rAF(requestAnimationFrame):

์‹œ์Šคํ…œ์ด ํ”„๋ ˆ์ž„์„ ๊ทธ๋ฆด ์ค€๋น„๊ฐ€ ๋˜๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ”„๋ ˆ์ž„์„ ํ˜ธ์ถœํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์›นํŽ˜์ด์ง€๋ฅผ ๋ณด๋‹ค ์›ํ™œํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์‹ค์ œ ํ™”๋ฉด์ด ๊ฐฑ์‹ ๋˜์–ด ํ‘œ์‹œ๋˜๋Š” ์ฃผ๊ธฐ์— ๋”ฐ๋ผ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํ”„๋ ˆ์ž„ ์‹œ์ž‘ ์‹œ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•ด์ฃผ์–ด ๋ฐ€๋ฆผ ํ˜„์ƒ์„ ๋ฐฉ์ง€ํ•ด์ค€๋‹ค.

  1. ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋™์ž‘ ์ค‘์ง€
  • setInterval: ๋ธŒ๋ผ์šฐ์ €์˜ ๋‹ค๋ฅธ ํƒญ ํ™”๋ฉด์„ ๋ณด๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ตœ์†Œํ™”๋˜์–ด ์žˆ์„ ๋•Œ ๊ณ„์† ํƒ€์ด๋จธ๊ฐ€ ๋Œ์•„ ์ฝœ๋ฐฑ์„ ํ˜ธ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์Šคํ…œ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„ O & ๋ถˆํ•„์š”ํ•œ ์ „๋ ฅ์„ ์†Œ๋ชจ O
  • requestAnimationFrame: ํŽ˜์ด์ง€๊ฐ€ ๋น„ํ™œ์„ฑํ™” ๋œ ์ƒํƒœ์ด๋ฉด ํŽ˜์ด์ง€ ํ™”๋ฉด ๊ทธ๋ฆฌ๊ธฐ ์ž‘์—…๋„ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์ผ์‹œ ์ค‘์ง€๋จ์œผ๋กœ CPU ๋ฆฌ์†Œ์Šค/๋ฐฐํ„ฐ๋ฆฌ ๋‚ญ๋น„ X
  1. ๋””์Šคํ”Œ๋ ˆ์ด ์ฃผ์‚ฌ์œจ์— ๋งž๊ฒŒ ํ˜ธ์ถœ ํšŸ์ˆ˜
    = setInterval๊ณผ requestAnimationFrame์˜ ๊ฒฐ์ •์ ์ธ ์ฐจ์ด์ 
    = setInterval ์—์„œ๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ฐ„๊ฒฉ์„ ์‹œ๊ฐ„์„ ์ง€์ •ํ•ด์ฃผ๊ณ  ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ์„ค์ •
    = rAF์—์„œ๋Š” ๋ชจ๋‹ˆํ„ฐ์˜ ์ฃผ์‚ฌ์œจ์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ฅด๊ฒŒ ๋˜์–ด ์ตœ์ ํ™” ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฌํ•œ ํŠน์„ฑ ๋•Œ๋ฌธ์— rAF๋Š” ์Šคํฌ๋กค ์ด๋ฒคํŠธ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์œผ๋กœ๋„ ์“ฐ์ด๊ธฐ๋„ ํ•œ๋‹ค.
  • Animation Frames: ๋ธŒ๋ผ์šฐ์ €์˜ ๋ Œ๋”๋ง ์—”์ง„์ด ๋‹ค์Œ ํ”„๋ ˆ์ž„์„ ๊ทธ๋ฆฌ๊ธฐ ์ „์— ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” rAF์— ๋“ฑ๋กํ•œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์„ ๋‹ด๋Š” Queue
  • ์šฐ์„ ์ˆœ์œ„๋Š” Microtask๋ณด๋‹ค๋Š” ๋‚ฎ๊ณ , Task๋ณด๋‹ค๋Š” ๋†’๋‹ค.

  1. Microtask queue: Promise ๊ฐ์ฒด, Mutation Observer ๊ฐ์ฒด๋ฅผ ์ฒ˜๋ฆฌ (๊ฐ€์žฅ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์Œ)
  2. Animation frames - requestAnimationFrame ์™€ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ € ๋ Œ๋”๋ง๊ณผ ๊ด€๋ จ๋œ ํƒœ์Šคํฌ ์ฒ˜๋ฆฌย 
  3. Task queue: ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜, setTimeout ๋ฐ setInterval ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ฒ˜๋ฆฌ
const rocket = document.querySelector('.rocket');
const value = document.querySelector('.value');
let yPos = 0;
let rafId;

// ์ฝœ๋ฐฑ ํ•จ์ˆ˜
const render = () => {
  yPos += 2; // y ์ขŒํ‘œ ์ฆ๊ฐ€

  rocket.style.transform = `translateY(${-yPos}px)`; // ๋กœ์ผ“์„ ์œ„๋กœ ์˜ฌ๋ฆฌ๊ธฐ
  value.innerHTML = yPos; // ์นด์šดํ„ฐ ํ‘œ์‹œ

  // ๋งŒ์•ฝ ๋กœ์ผ“ ์œ„์น˜๊ฐ€ ์ผ์ • y์ขŒํ‘œ๊ฐ’์ผ ๊ฒฝ์šฐ requestAnimationFrame ์ข…๋ฃŒ
  if (yPos >= 500) {
    cancelAnimationFrame(rafId);
    return;
  }

  rafId = requestAnimationFrame(render); // rAF ๋ฐ˜๋ณต ํ˜ธ์ถœ
}

requestAnimationFrame(render); // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ์ž‘
profile
๐Ÿ”ฅ๐ŸฆŠ

0๊ฐœ์˜ ๋Œ“๊ธ€