๐ŸŒŸ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜์š”?

MISO :-)

๐ŸŒŸ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜์š”?

2023๋…„ 02์›” 26์ผ

13๋ถ„

0๋ช…์˜ ์‚ฌ๋žŒ์ด ์ฝ์–ด๋ดค์–ด์š”

JavaScript์™€ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋ผ๋Š” ๊ฒƒ์€ ์—”์ง„๋งˆ๋‹ค ๋‹จ ํ•˜๋‚˜์˜ ํ˜ธ์ถœ ์Šคํƒ(call stack)์ด ์กด์žฌํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ธฐ์— ๋ชจ๋“  ์‹คํ–‰์€ ํ•˜๋‚˜์”ฉ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ฝ”๋“œ๋“ค์€ ํ˜„์žฌ์˜ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธธ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ๊ฐœ๋… ์žก๊ธฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„

JS ์—”์ง„์˜ ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ๋Š” Google์˜ V8 ์—”์ง„์ž…๋‹ˆ๋‹ค. V8 ์—”์ง„์€ ํฌ๋กฌ๊ณผ Node.js์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์—”์ง„์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์—”์ง„์€ ๋‘ ๊ฐ€์ง€์˜ ๋Œ€ํ‘œ ์š”์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • Memory Heap: ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ด ์ผ์–ด๋‚˜๋Š” ๊ณณ
  • Call Stack: ์ฝ”๋“œ ์‹คํ–‰์— ๋”ฐ๋ผ ํ˜ธ์ถœ ์Šคํƒ์ด ์Œ“์ด๋Š” ๊ณณ

๋Ÿฐํƒ€์ž„(Runtime)

๊ฑฐ์˜ ๋ชจ๋“  JavaScript ๊ฐœ๋ฐœ์ž๋“ค์€ setTimeout ๊ฐ™์€ ๋ธŒ๋ผ์šฐ์ € ๋‚ด์žฅ API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น API๋Š” JS ์—”์ง„์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ๋„ ์•„๋‹Œ๋ฐ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑธ๊นŒ์š”?

ํ˜„์‹ค์€ ์กฐ๊ธˆ ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €์—๋Š” JS ์—”์ง„ ์™ธ์—๋„ ๋‹ค์–‘ํ•œ ์š”์†Œ๋“ค์ด ๋งŽ์Šต๋‹ˆ๋‹ค.

DOM, Ajax, setTimeout๊ณผ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๊ณตํ•˜๋Š” API๋“ค์„ Web API๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆผ ์•„๋ž˜ ์ชฝ์—” ์ด๋ฒคํŠธ ๋ฃจํ”„(event loop)์™€ ์ฝœ๋ฐฑ ํ(callback queue)๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šคํƒ(Call Stack)

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ž…๋‹ˆ๋‹ค.

์ด ๋ง์€ ํ•˜๋‚˜์˜ ํ˜ธ์ถœ ์Šคํƒ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ๋ฒˆ์— ํ•œ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šคํƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ํ”„๋กœ๊ทธ๋žจ ์ƒ์—์„œ ์–ด๋””์— ์žˆ๋Š”์ง€๋ฅผ ๊ธฐ๋กํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

๋งŒ์•ฝ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ ์Šคํƒ์˜ ์ตœ์ƒ๋‹จ์— ์กด์žฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด(๋ฆฌํ„ด ๊ฐ’์„ ๋Œ๋ ค์ค€๋‹ค๋ฉด), ์Šคํƒ์˜ ์ตœ์ƒ๋‹จ์— ์กด์žฌํ•˜๋˜ ๊ฒƒ์ด ์‚ฌ๋ผ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์ด ์Šคํƒ์˜ ์—ญํ• ์ž…๋‹ˆ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

function multiply(x, y) {
  return x * y;
}
function printSquare(x) {
  var s = multiply(x, x);
  console.log(s);
}
printSquare(5);

์—”์ง„์ด ์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ, ํ˜ธ์ถœ ์Šคํƒ์€ ๋น„์›Œ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šคํƒ์˜ ๊ฐ ํ•ญ๋ชฉ์„ ์Šคํƒ ํ”„๋ ˆ์ž„(Stack Frame)์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

๋™์‹œ์„ฑ & ์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop)

ํ˜ธ์ถœ ์Šคํƒ์— ๊ต‰์žฅํžˆ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์žˆ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ JavaScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณต์žกํ•œ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜์„ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ์š”.

์ด๊ฒŒ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‚˜์š”?

๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด ๋ฌธ์ œ๋ฅผ ๋ธŒ๋ผ์šฐ์ € ๊ด€์ ์œผ๋กœ ๋ณด์ž๋ฉด ํ˜ธ์ถœ ์Šคํƒ์˜ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋™์•ˆ ๋ธŒ๋ผ์šฐ์ €๋Š” ์•„๋ฌด ์ž‘์—…๋„ ํ•˜์ง€ ๋ชปํ•˜๊ณ  ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๋Š” ๋ Œ๋”๋ง๋„ ๋ชปํ•˜๊ณ  ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ์ € ๊ฐ‡ํžŒ ์ƒํƒœ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋งค๋„๋Ÿฝ๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™”๋ฉด UI๋ฅผ ์›ํ•œ๋‹ค๋ฉด ์œ„ ๊ฒฝ์šฐ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์ด ๋ฟ๋งŒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์˜ ๋งŽ์€ ์ผ๋“ค์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ํ™”๋ฉด์ด ์˜ค๋žซ๋™์•ˆ ์‘๋‹ตํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋„์šฐ๋ฉฐ ํŽ˜์ด์ง€๋ฅผ ์ข…๋ฃŒํ•  ๊ฒƒ์ธ์ง€ ๋ฌป์Šต๋‹ˆ๋‹ค.

์ด ์ƒํ™ฉ์€ ์ ˆ๋Œ€ ์ด์ƒ์ ์ธ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐ€์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ๋™์ž‘์„ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๊ณ  ๋ธŒ๋ผ์šฐ์ €์˜ ์‘๋‹ต๋„ ๋Š์ง€ ์•Š์œผ๋ฉฐ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

์ •๋‹ต์€ ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ์ž…๋‹ˆ๋‹ค.

์ด์ œ๋Š” ์ž์„ธํ•˜๊ฒŒ ์ด์•ผ๊ธฐํ•ด๋ด…์‹œ๋‹ค!

๋ฉ”์ธ ์Šค๋ ˆ๋“œ์™€ ํ˜ธ์ถœ ์Šคํƒ ์ž์„ธํžˆ ์ดํ•ดํ•˜๊ธฐ

๋ช‡ ๊ฐ€์ง€ ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์™€ ํ˜ธ์ถœ ์Šคํƒ์˜ ์‹คํ–‰ ํ๋ฆ„์„ ์ดํ•ดํ•ด๋ด…์‹œ๋‹ค!

ํ˜ธ์ถœ ์Šคํƒ ์ดํ•ดํ•˜๊ธฐ

function bar() {
  console.log('bar');
}
function jazz() {
  console.log('jazz');
  bar();
}
function foo() {
  console.log('foo');
  jazz();
}
const btn = document.getElementById('foo');
btn.addEventListener('click', foo, false);

// Output (๋ฒ„ํŠผ ํด๋ฆญ ์‹œ)
// foo
// jazz
// bar
  1. Global Execution Context(GEC)๊ฐ€ ์ƒ์„ฑ๋˜์–ด ํ˜ธ์ถœ ์Šคํƒ์— ํ‘ธ์‹œ๋ฉ๋‹ˆ๋‹ค.
  2. foo ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  3. foo()์— ๋Œ€ํ•œ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ํ˜ธ์ถœ ์Šคํƒ์— ํ‘ธ์‹œ๋œ ๋’ค ํ•œ ์ค„์”ฉ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  4. foo() ํ•จ์ˆ˜์—์„  โ€œfooโ€๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•˜๊ณ  jazz() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  5. jazz()์— ๋Œ€ํ•œ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๊ณ  ํ˜ธ์ถœ ์Šคํƒ์˜ ์ƒ๋‹จ์— ํ‘ธ์‹œ๋ฉ๋‹ˆ๋‹ค.
  6. jazz()๋Š” โ€œjazzโ€๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•˜๊ณ  bar() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  7. bar()์— ๋Œ€ํ•œ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๊ณ  ํ˜ธ์ถœ ์Šคํƒ์˜ ์ƒ๋‹จ์— ํ‘ธ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„ โ€œbarโ€๊ฐ€ ์ฝ˜์†”์— ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  8. bar()๊ฐ€ ๋ฆฌํ„ด๋˜๋ฉด ์Šคํƒ์—์„œ ์ œ๊ฑฐ(pop)๋ฉ๋‹ˆ๋‹ค.
  9. jazz()์™€ foo()๋ชจ๋‘ ์ œ๊ฑฐ๋˜์–ด ์Šคํƒ์˜ ๋งˆ์ง€๋ง‰์— ๋„๋‹ฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  10. ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜๋ฉด GEC๋„ ์ œ๊ฑฐ๋˜๊ณ  ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„์›Œ์ง‘๋‹ˆ๋‹ค.

์œ„ ๊ณผ์ •์„ ํ†ตํ•ด ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์— ์ถ”๊ฐ€(push)๋˜๊ณ , ์ œ๊ฑฐ(pop)๋˜๋Š” ๋ฐฉ์‹์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ „์—ญ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ(Global Execution Context): GEC๋Š” JS ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰์„ ์‹œ์ž‘ํ•  ๋•Œ ์ƒ๊ธฐ๋Š” ๊ธฐ๋ณธ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ํ†ตํ•ด window ๊ฐ์ฒด์™€ this ํ‚ค์›Œ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.

GEC๋Š” ์‹คํ–‰์ด ์ข…๋ฃŒ๋˜๋ฉด ํ˜ธ์ถœ ์Šคํƒ์—์„œ ์ œ๊ฑฐ๋˜๊ณ  ECMAScript ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „ ๋‹ค์‹œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. (ECMA ๋ช…์„ธ์—์„œ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์— ๋Œ€ํ•ด ํ™•์ธํ•ด๋ณด์„ธ์š”!)

์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

ํ˜ธ์ถœ ์Šคํƒ ํญํŒŒ์‹œํ‚ค๊ธฐ

์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ฝ˜์†”์— ๋‚˜ํƒ€๋‚˜๋Š” ์Šคํƒ ํŠธ๋ ˆ์ด์Šค(Stack Trace)๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์ „๊นŒ์ง€์˜ ์Šคํƒ๋“ค์„ ๊ผฌ๋ฆฌ๋ฅผ ๋ฌผ๋ฉฐ ์Šคํƒ์„ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// foo.js

function foo() {
  throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
  foo();
}
function start() {
  bar();
}
start();

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์Šคํƒ์˜ ๊ผฌ๋ฆฌ๋ฅผ ๋ฌผ๋ฉฐ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋ฉ๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šคํƒ์˜ ์ตœ๋Œ€์น˜๊ฐ€ ๋˜๋ฉด โ€œ์Šคํƒ ํญํŒŒ์‹œํ‚ค๊ธฐ(Blowing the stack)โ€๊ฐ€ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์ฝ”๋“œ๋ฅผ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š๊ณ  ์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ๋งค์šฐ ์‰ฝ๊ฒŒ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function foo() {
  foo();
}
foo();

์—”์ง„์ด ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ, ํ•จ์ˆ˜์ธ foo๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” foo ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ž๊ธฐ ์ž์‹ ์„ ํ˜ธ์ถœํ•˜๋Š” ์žฌ๊ท€ ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํ˜ธ์ถœ ์Šคํƒ์— ๋˜‘๊ฐ™์€ ํ•จ์ˆ˜๊ฐ€ ๊ณ„์† ์Œ“์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์‹คํ–‰์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์–ด๋–ค ์‹œ์ ์— ํ˜ธ์ถœ ์Šคํƒ์˜ ์ตœ๋Œ€์น˜๋ฅผ ๋„˜์–ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ด๋Ÿฐ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜์€ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์ผ์–ด๋‚˜๋Š” ๋ฐ๋“œ๋ฝ(deadlocks) ๊ฐ™์€ ๋ณต์žกํ•œ ๋ฌธ์ œ๋“ค์„ ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ์— ๊ต‰์žฅํžˆ ์‰ฝ์Šต๋‹ˆ๋‹ค.

์ถœ์ฒ˜: https://m.blog.naver.com/smc503/221920305642

๊ทธ๋Ÿฌ๋‚˜ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๊ต‰์žฅํžˆ ์ œํ•œ์ ์ž…๋‹ˆ๋‹ค. ํ•œ ๊ฐœ์˜ ํ˜ธ์ถœ ์Šคํƒ์ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” JavaScript์—์„œ๋Š” ์ž‘์—…์ด ๋Š๋ ค์ง€๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

๋ฉ”์ธ ์Šค๋ ˆ๋“œ ์ฐจ๋‹จํ•˜๊ธฐ

๋งŒ์•ฝ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ์— ๋ฌดํ•œ ๋ฃจํ”„๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค!

// ์ด ํ•จ์ˆ˜๊ฐ€ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ๋„๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
function blockMainThread() {
  while (true);
}

//๋ฉ”์ธ ์Šค๋ ˆ๋“œ ๋ฒ„ํŠผ์— ์ด๋ฒคํŠธ๋ฅผ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
const btn = document.getElementById('block');
btn.addEventListener('click', blockEventLoop);

๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด blockMainThread() ํ•จ์ˆ˜์˜ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์œผ๋กœ ํ‘ธ์‹œ๋˜๊ณ  ๋ฌดํ•œ ๋ฃจํ”„๋กœ ์ธํ•ด ๊ณ„์† ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. (GEC๋Š” ํ•ญ์ƒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค)

์ด๋กœ ์ธํ•ด ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋Š” blockMainThread() ํ•จ์ˆ˜๋ฅผ ๊ณ„์† ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋ฉฐ ์•„๋ฌด ๊ฒƒ๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๊ธฐ์— ๋ชจ๋“  UI ์‘๋‹ต์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜๋ฉด ํƒญ์€ ์™„์ „ํžˆ ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ์ƒํƒœ๊ฐ€ ๋˜๋ฉฐ ํƒญ์—์„œ ์•„๋ฌด๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. โ€™์Šค๋ ˆ๋“œ๋ฅผ ๊ฐ•์ œ๋กœ ์ค‘์ง€ํ•˜๋ผโ€™๋Š” ์ค‘์ง€ ํ”„๋กฌํ”„ํŠธ ์ฐฝ์„ ๋ณด๊ธฐ ์ „๊นŒ์ง€ ๋ง์ด์ฃ ..!

์ด์ œ ์ €ํฌ๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ธ์ง€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

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

๊ฐœ๋ฐœ์ž๊ฐ€ ์ •ํ•œ ์‹œ๊ฐ„ ์ดํ›„์—์•ผ ๋ฌด์–ธ๊ฐ€๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์›ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž์˜ ๊ฒฝํ—˜์— ๊ต‰์žฅํžˆ ์ข‹์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ Web APIs, ์ด๋ฒคํŠธ ๋ฃจํ”„(event loop), ์—ฌ๋Ÿฌ ๊ฐœ์˜ Queue๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋‹จ์ผ ์Šค๋ ˆ๋“œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ ํ•ด๊ฒฐ

Web APIs

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์šฐ๋ฆฌ์—๊ฒŒ ๋…ธ์ถœ๋˜๋Š” ์ˆ˜๋งŽ์€ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ๊ณผ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค. Web APIs๋Š” ๋” ๋น ๋ฅธ ์–ธ์–ด(ex: ํฌ๋กฌ์˜ C++)๋กœ ๊ตฌํ˜„๋˜์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

  1. ๋„คํŠธ์›Œํฌ ์š”์ฒญ
  2. DOM ์กฐ์ž‘
  3. Local Storage
  4. ๋ธ”๋ฃจํˆฌ์Šค
  5. ํ™”๋ฉด ์บก์ฒ˜
  6. ์œ„์น˜
  7. setTimeout, ํƒ€์ด๋จธ

๋“ฑ๋“ฑโ€ฆ ์ €ํฌ๊ฐ€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” console.log๋„ ์ฝ˜์†” Web API์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ Web APIs ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•ด๋ณด์„ธ์š”!

Web API์˜ ํŠน์ง•์€ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ํšจ๊ณผ์ ์œผ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ์‹คํ–‰๋˜๊ณ  ํƒญ์˜ ๊ธฐ๋ณธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์Šค๋ ˆ๋“œ๋ฅผ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด Web API์ธ console.log๋„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋ ๊นŒ์š”?

๋„ค! ๋‹ค๋ฅธ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ console.log๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ console.log๋Š” ์ฝœ๋ฐฑ์„ ํฌํ•จํ•˜์ง€ ์•Š๊ธฐ์— ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ํ•  ์ผ์„ ๋„˜๊ธด ํ›„ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฝ˜์†”์„ ์ถœ๋ ฅํ•œ ๋’ค ๋‹ค์‹œ JS ์—”์ง„์œผ๋กœ ๋Œ์•„์˜ค์ง„ ์•Š์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋น„๋™๊ธฐ ํŠน์„ฑ์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ ๋ชจ๋“  Web API๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ํšจ๊ณผ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ JS ์—”์ง„์—์„œ ๋ชจ๋“  ๋Š๋ฆฐ ์ž‘์—…๋“ค์„ ๋„˜๊น๋‹ˆ๋‹ค.

์ถœ์ฒ˜: https://lightmap.dev/how-does-javascript-even-work-1

๊ทธ๋Ÿฌ๋‚˜ Web API์—์„œ ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ, ๋””์Šคํฌ ์ ‘๊ทผ ๋“ฑ์˜ ์ฝœ๋ฐฑ์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ ๊ฐ™์€ ๊ฒฝ์šฐ์— ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์™€ ์–ด๋–ป๊ฒŒ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

์—ฌ๊ธฐ์—์„œ ๋‹ค์–‘ํ•œ ํ์™€ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Queues

  1. Task Queue (= Callback Queue)
  2. Render Queue
  3. Micro-Task Queue (= Job Queue)

๋จผ์ € Task Queue์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๊ณ  Task Queue๋ฅผ ์ด์šฉํ•˜์—ฌ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„ ์ „์ฒด ์‹œ์Šคํ…œ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ์•„๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

Task Queue

Callback Queue, Message Queue๋ผ๊ณ ๋„ ๋ถˆ๋ฆฌ๋Š” Task Queue๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ ์ž…์„ ์ถœ(FIFO) ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. (์ž์„ธํ•œ Queue ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋Š” ์—ฌ๊ธฐ์„œ ํ™•์ธํ•ด๋ณด์„ธ์š”)

๋”ฐ๋ผ์„œ Web API๊ฐ€ ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋ฉด ์ด๋Ÿฐ ์ž‘์—…์˜ ์ฝœ๋ฐฑ์„ Callback Queue๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” Task Queue์—๊ฒŒ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

์ถœ์ฒ˜: https://lightmap.dev/how-does-javascript-even-work-1

Event Loop

์ถœ์ฒ˜: http://latentflip.com/loupe

๋ชจ๋“  JS ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ณ  ํ˜ธ์ถœ ์Šคํƒ์ด ๋นˆ๋‹ค๋ฉด ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” Task Queue์— ์ง„ํ–‰ํ•  ์ž‘์—…์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ํ˜ธ์ถœ ์Šคํƒ์— ํ‘ธ์‹œํ•˜์—ฌ ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋žจ์€ ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์ง„ํ–‰์ด ๋˜๋Š” ๊ฒƒ์ด์ฃ !

  1. ํ˜ธ์ถœ ์Šคํƒ์ด Web API ๊ด€๋ จ๋œ ์ž‘์—…์„ ๋งŒ๋‚˜๋ฉด Web API์—๊ฒŒ ๋„์›€์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
  2. Web API๋Š” ํ˜ธ์ถœ ์Šคํƒ์— ์™„๋ฃŒ๋กœ ํ‘œ์‹œํ•œ ๋’ค Web API๋กœ ํ•ด๋‹น ์ž‘์—…์„ ๋„˜๊น๋‹ˆ๋‹ค.
  3. ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๊ณ  ์ฝœ๋ฐฑ์„ Task Queue(Callback Queue)๋กœ ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค.
  4. ์ผ๋ฐ˜ ์ฝ”๋“œ ์‹คํ–‰์ด ์™„๋ฃŒ๋œ ๋’ค ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„์–ด ์žˆ์œผ๋ฉฐ GEC๋„ ์ œ๊ฑฐ๋˜๋ฉด ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ผ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  5. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” Task Queue์˜ ์ž‘์—…์„ ํ™•์ธํ•˜๊ณ  ์ž‘์—…์„ ํ•˜๋‚˜์”ฉ Call Stack์— ํ‘ธ์‹œํ•œ ๋’ค ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  6. GEC๋Š” ํ•ญ์ƒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ƒ์„ฑ๋˜๋ฏ€๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ž‘์—…์„ ํ‘ธ์‹œํ•  ๋•Œ๋„ GEC๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

Chrome์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„

์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” V8์˜ ์ผ๋ถ€์ผ๊นŒ์š”? ใ„ด ์•„๋‹™๋‹ˆ๋‹ค!!!!!!!!!!!!!!

์ถœ์ฒ˜: https://lightmap.dev/how-does-javascript-even-work-1

์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ V8์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์–ด๋–ป๊ฒŒ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„์—ˆ๋Š”์ง€ ํŒ๋‹จํ• ๊นŒ์š”?

Chrome ๋ธŒ๋ผ์šฐ์ €์—์„œ V8์€ ๋งค์šฐ ์ธ๊ธฐ์žˆ๋Š” ์˜คํ”ˆ ์†Œ์Šค์ธ ์ด๋ฒคํŠธ ์•Œ๋ฆผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ libevent์™€ ํ•จ๊ป˜ ์ œ๊ณต๋˜์–ด Chrome์— ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด Node์—์„œ๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ธฐ๋Šฅ์„ ์œ„ํ•ด V8๊ณผ ํ•จ๊ป˜ libUV๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ธก ์‹คํ–‰์„ ์šฉ์ดํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋“œ์—์„œ ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ตฌํ˜„์ด ํ•„์š”ํ•˜๊ธฐ์— Chrome ๋ธŒ๋ผ์šฐ์ €์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„์™€๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„ ์ดํ•ดํ•˜๊ธฐ

๋ฌดํ•œ ์žฌ๊ท€ ์ƒํ™ฉ

ํ˜ธ์ถœ ์Šคํƒ์„ ํญํŒŒํ–ˆ๋˜ ํ”„๋กœ๊ทธ๋žจ์„ ๊ธฐ์–ตํ•˜์‹œ๋‚˜์š”? ์ด์ œ ์•„๋ฌด ๋ฌธ์ œ ์—†์ด ์ž‘๋™ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ์•ฝ๊ฐ„์˜ ๋ณ€๊ฒฝ์„ ํ†ตํ•ด ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

function foo(i) {
  console.log(i);
  setTimeout(() => foo(i + 1), 0);
}

const btn = document.getElementById('foo');
btn.addEventListener('click', () => foo(0), false);

setTimeout์— ์ž‘์„ฑ๋œ ์ง€์—ฐ ์‹œ๊ฐ„์ด 0์ด๋ผ๊ณ  ๋ช…์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์™ธ๋Š” ํญ๋ฐœํ–ˆ๋˜ ํ”„๋กœ๊ทธ๋žจ๊ณผ ๋™์ผํ•œ ํ”„๋กœ๊ทธ๋žจ์ž…๋‹ˆ๋‹ค. ์ž‘๋™๋ฐฉ์‹์„ ์ดํ•ดํ•ด๋ด…์‹œ๋‹ค!

  1. GEC๊ฐ€ ์ƒ์„ฑ๋˜์–ด ํ˜ธ์ถœ ์Šคํƒ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  2. ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  3. foo() ํ•จ์ˆ˜ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  4. foo()๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์ฒซ ๋ฒˆ์งธ ํ˜ธ์ถœ์—์„œ i๊ฐ’์„ 0์œผ๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  5. Web API์ธ setTimeout์„ ๋งŒ๋‚˜๋ฉด ํ˜ธ์ถœ ์Šคํƒ์—์„œ Web API ์ชฝ์ธ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ž‘์—…์„ ๋„˜๊น๋‹ˆ๋‹ค.
  6. foo() ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰์— ๋„๋‹ฌํ•˜์—ฌ foo() ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ์‚ฌ๋ผ์ง€์ง€๋งŒ ์—ฌ์ „ํžˆ setTimeout์ด ์‹คํ–‰๋˜์ง€ ์•Š์•„ ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  7. ์ง€์—ฐ ์‹œ๊ฐ„์ด 0์ด๊ธฐ์— setTimeout์˜ ์ฝœ๋ฐฑ์ด Task Queue์—๊ฒŒ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
  8. foo(i+1)์ธ Task Queue์˜ ํ•จ์ˆ˜๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์˜ํ•ด ๋นˆ ํ˜ธ์ถœ ์Šคํƒ์œผ๋กœ ํ‘ธ์‹œ๋˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  9. 3๋‹จ๊ณ„๋กœ ๋‹ค์‹œ ๋Œ์•„๊ฐ€ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์š”์ ์€ ๊ณ„์† ์‹คํ–‰ํ•˜๋ฉฐ ํ˜ธ์ถœ ์Šคํƒ์„ ์ฑ„์šฐ์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ชจ๋‘ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๊ณตํ•˜๋Š” setTimeout() API ๋•๋ถ„์ž…๋‹ˆ๋‹คโ€ฆ!

ํƒ€์ž„์•„์›ƒ ์ •๋ ฌ(Timeout Sort!!!)

๋ฒ„๋ธ” ์ •๋ ฌ, ์‚ฝ์ž… ์ •๋ ฌ, ์„ ํƒ ์ •๋ ฌ์— ๋Œ€ํ•ด ๋“ค์–ด๋ณด์…จ๊ฒ ์ง€๋งŒ ํƒ€์ž„์•„์›ƒ ์ •๋ ฌ์— ๋Œ€ํ•ด ์•Œ๊ณ  ๊ณ„์‹ ๊ฐ€์š”?

setTimeout() API๋ฅผ ์ด์šฉํ•˜์—ฌ ์ˆซ์ž๋ฅผ ์ •๋ ฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

let arr = [10, 100, 500, 20, 35];

arr.forEach((item) => {
  setTimeout(() => console.log(item), item);
});
  1. ํ•ญ์ƒ GEC๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  2. ๋ชจ๋“  ๋ฐฐ์—ด ์š”์†Œ๋Š” setTimeout๋ฅผ ํ˜ธ์ถœ๋˜์–ด ์Šคํƒ์— ํ‘ธ์‹œ๋œ ํ›„ ๋ธŒ๋ผ์šฐ์ €๋กœ ์˜คํ”„๋กœ๋“œ ๋ฉ๋‹ˆ๋‹ค.(๋„˜๊น๋‹ˆ๋‹ค.)
  3. setTimeout์€ ๋ฐฐ์—ด์— ์ •์˜๋œ ์ˆซ์ž๋งŒํผ ์ง€์—ฐ๋ฉ๋‹ˆ๋‹ค.
  4. ๊ฐ€์žฅ ์งง์€ 10ms๊ฐ€ ๋๋‚˜๋ฉด Task Queue๋กœ ํ‘ธ์‹œ๋˜๊ณ  ์ด๋ฒคํŠธ ๋ฃจํ”„๋กœ ์ธํ•ด ์ฝœ ์Šคํƒ์œผ๋กœ ํ‘ธ์‹œ๋˜๊ณ  10์ด ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค.
  5. ์ดํ›„ 20, 35, 100, 500 ์ˆœ์œผ๋กœ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๋ฉ‹์ง€์ง€ ์•Š๋‚˜์š”?

Render Queue

Render Queue(์ดํ•˜ ๋ Œ๋” ํ)๋Š” ๋ชจ๋“  ํ™”๋ฉด ์—…๋ฐ์ดํŠธ ํ˜น์€ repaint(์ดํ•˜ ๋ฆฌํŽ˜์ธํŠธ) ์ „์— ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ๋ชจ๋“  ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„ ์‹œ์Šคํ…œ์˜ ๋˜ ๋‹ค๋ฅธ ํ ์ž…๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ •๊ธฐ์ ์œผ๋กœ ์ด๋Ÿฐ ๋ฆฌํŽ˜์ธํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ํšจ๊ณผ์™€ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € ์ž‘๋™ ๊ณผ์ •์„ ์ดํ•ดํ•˜์‹  ๋ถ„๋“ค์ด๋ผ๋ฉด ๋ฆฌํŽ˜์ธํŠธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์–ด๋–ค ์ˆœ์„œ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ์•„์‹ค๊ฒ๋‹ˆ๋‹ค.

์œ„์˜ ๋‹ค์ด์–ด๊ทธ๋žจ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ž‘์—…(๋ฆฌํŽ˜์ธํŠธ ์ „ ์ž‘์—…)๊ณผ ๋ฆฌํŽ˜์ธํŠธ์™€ ๊ด€๋ จ๋œ 4๊ฐ€์ง€ ์ฃผ์š” ๋‹จ๊ณ„๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ณผ์ • ํ˜น์€ โ€œBrowser Rendering Queue in-depthโ€ ๊ธ€์„ ํ™•์ธํ•ด๋ณด์„ธ์š”!

๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฆฌํŽ˜์ธํŠธ๋ฅผ ํ•  ๋•Œ๋งˆ๋‹ค ๋ชจ๋“  ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ๋งŒ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ(main thread)๊ฐ€ ์œ ํœด ์ƒํƒœ์ด๊ฑฐ๋‚˜ ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„์–ด ์žˆ์„ ๋•Œ๋งŒ ์ด ์†๋„๋กœ ๋ฆฌํŽ˜์ธํŠธํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ธ ์ž‘์—…์ด ์žˆ๋Š” ๋™์•ˆ์—๋Š” ๋ฆฌํŽ˜์ธํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๊ธฐ์— ์ž‘์—…์ด ๋Œ€๊ธฐ ์ค‘์ธ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €๋Š” ๊ต๋ฌ˜ํ•˜๊ฒŒ ๋ช‡ ๊ฐ€์ง€ ์ž‘์—…์„ ์ง„ํ–‰ํ•œ ํ›„ ๋ Œ๋”๋ง ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๊ณ  ๋น ๋ฅด๊ฒŒ ๋‹ค์‹œ ๋Œ์•„์˜ค๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ์ด์•ผ๊ธฐ ํ–ˆ๋˜ ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํ˜ธ์ถœ ์Šคํƒ์„ ํญํŒŒ์‹œ์ผฐ๋˜ ์˜ˆ์ œ์™€ setTimeout์„ ํ†ตํ•ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋˜ ์˜ˆ์ œ๋ฅผ ๊ธฐ์–ตํ•˜์‹œ๋‚˜์š”?

setTimeout์„ ์ด์šฉํ•˜๋ฉด ํ•ด๋‹น ๋ถ€๋ถ„์€ ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„์–ด์žˆ๋Š” ์ƒํ™ฉ์ด ์žˆ๊ธฐ์— ๋ Œ๋” ์ž‘์—…์ด ๋“ค์–ด์˜ฌ ๊ธฐํšŒ๊ฐ€ ์ƒ๊ฒจ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

latentflip.com/loupe ์‚ฌ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๋ Œ๋” ํ๋ฅผ ์ง์ ‘ ํ™”๋ฉด์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋Œ์•„๊ฐ€์„œ ๋ฆฌํŽ˜์ธํŠธ ์ „์— ์ž‘์—…์„ ์–ด๋–ป๊ฒŒ Queue(์ดํ•˜ ํ)์— ๋„ฃ์„ ์ˆ˜ ์žˆ์„๊นŒ์š”?

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋ Œ๋”๋ง ํ์— ์ž‘์—…์„ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ฉ”์„œ๋“œ(Web API) requestAnimationFrame๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋Ÿฐ ์ž‘์—…์„ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ Œ๋” ํ์—๋Š” ์‹คํ–‰ ์ค‘์— ๋ฌด์–ธ๊ฐ€๋ฅผ ์ถ”๊ฐ€ํ•  ๊ฒฝ์šฐ ๋‹ค์Œ ํŽ˜์ธํŠธ ์ฃผ๊ธฐ์— ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•˜๋Š” ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€๋Š” Microtask Queue(์ดํ•˜ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ)์— ๋“ค์–ด๊ฐ€๊ธฐ ์ „ ๋ Œ๋”๋ง ํ์™€ ์ด๋ฒคํŠธ ๋ฃจํ”„์™€ ํ˜ธ์ถœ ์Šคํƒ๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ํ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„  ES6์—์„œ ์ƒˆ๋กญ๊ฒŒ ์ƒ๊ธด ๊ฐœ๋…, Promise์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Promises

์ด์ „ ๊ธ€์—์„œ ์‹œ๊ฐ„์„ ์ง€์—ฐํ•˜๋Š” ์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉด ์ฝœ๋ฐฑ์œผ๋กœ ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ฝœ๋ฐฑ ์•ˆ์— ์ฝœ๋ฐฑ์ด ์žˆ๊ณ  ๊ทธ ์•ˆ์— ๋‹ค์‹œ ์ฝœ๋ฐฑ์ด ์žˆ๋‹ค๋ฉด ์ฝœ๋ฐฑ ์ง€์˜ฅ(callback hell)์— ๋น ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถœ์ฒ˜: https://dev.to/jerrycode06/callback-hell-and-how-to-rescue-it-ggj

์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Promise๊ฐ€ ES6์—์„œ ๋“ฑ์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Promise์—๋Š” 3๊ฐ€์ง€ ์ƒํƒœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. Resolved, ์ž‘์—…์ด ์™„๋ฃŒ๋œ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  2. Rejected, ์ž‘์—…์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  3. Pending, ์ž‘์—…์ด ์ง„ํ–‰๋˜๊ณ  ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
const p = new Promise((resolve, reject) => {
  const a = 1;
  if (!a) {
    reject(new Error('This Promise is Rejected'));
  } else {
    resolve('This Promise is resolved');
  }
});

p.then(() => {
  console.log('Successfully Resolved');
}).catch(() => {
  console.log('Rejected');
});

์ฝ”๋“œ๋ฅผ ํ†ตํ•ด Promise๋Š” Reject์™€ Resolve๋ผ๋Š” ์ƒํƒœ๋กœ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉด Resolve๋ฅผ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด Reject๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

Promise์— .then() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด promise๊ฐ€ resolve ์ƒํƒœ์ผ ๋•Œ ํ•ด๋‹น ๋ฉ”์„œ๋“œ ์•ˆ์— ์žˆ๋Š” ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด .catch() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด promise๊ฐ€ reject ์ƒํƒœ์ผ ๋•Œ ๊ฑฐ๋ถ€ ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

.finally() ๋Š” Promise์˜ ์ƒํƒœ ๊ฐ’์ด ํ™•์ •๋œ ๋’ค ์‹คํ–‰๋˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

Promise๋Š” Promise Chanining์ด๋ผ๋Š” ๊ฒƒ์„ ์ด์šฉํ•ด ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ ํ•ด๊ฒฐํ•˜๊ณ  async/await๋ฅผ ์ด์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์—์„œ Promise๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ์€ JS ๋™์ž‘ ๋ฐฉ์‹์— ์ง‘์ค‘ํ•˜์—ฌ Promise์™€ .then(), .catch() ์ฝœ๋ฐฑ์„ ์ฒ˜๋ฆฌํ•˜๋Š” Queue์— ๋Œ€ํ•ด ์ดํ•ดํ•ด๋ด…์‹œ๋‹ค!

MicroTask Queue

Microtask Queue(= Job Queue, ์ดํ•˜ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ)๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Promise๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํฅ๋ฏธ๋กœ์šด Queue์ž…๋‹ˆ๋‹ค.

๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ๋Š” ํƒœ์Šคํฌ ํ์™€ ๋ Œ๋”๋ง ํ๋ณด๋‹ค ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’์Šต๋‹ˆ๋‹ค. ์ฆ‰, ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์˜ ์ž‘์—…์ด ๋จผ์ € ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„๊ฒŒ๋˜๋ฉด ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์— ์ž‘์—…์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ์ž‘์—…์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์˜ ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋†’๊ธฐ์— ๋ชจ๋“  ์ž‘์—…์„ ์™„๋ฃŒํ•  ๋•Œ๊นŒ์ง€ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์˜ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด ๋™์ž‘์œผ๋กœ ์ธํ•ด ๋ฌดํ•œ ๋ฃจํ”„์™€ ์œ ์‚ฌํ•œ ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function blockEventLoop() {
  Promise.resolve().then(blockEventLoop);
}

const btn = document.getElementById('kill');
btn.addEventListener('click', blockEventLoop, false);

id๊ฐ€ kill์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋ชจ๋“  ์ž‘์—…์ด ์–ผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ž‘๋™ ์ˆœ์„œ๋ฅผ ํ†ตํ•ด ์ด์œ ๋ฅผ ์•Œ์•„๋ด…์‹œ๋‹ค.

  1. ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ณ  btn์— click ์ด๋ฒคํŠธ๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  2. id๊ฐ€ kill์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฆ…๋‹ˆ๋‹ค.
  3. ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ํ์— blockEventLoop ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  4. ํ˜ธ์ถœ ์Šคํƒ์€ ๋น„์–ด์žˆ๋Š” ์ƒํƒœ์ด๋ฏ€๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ promise๋ฅผ ํ˜ธ์ถœ ์Šคํƒ์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ promise๊ฐ€ ํ์— ์ถ”๊ฐ€๋˜๋Š” ์ž‘์—…์ด ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค.
  5. ๊ทธ๋ ‡๊ธฐ์— ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋Š” ์‰ฌ์ง€ ์•Š๊ณ  ์ผํ•˜๋ฉฐ ์ด๋กœ ์ธํ•ด ์ •์ง€๋œ ํ™”๋ฉด์œผ๋กœ ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์˜ˆ์‹œ๋ฅผ ํ•˜๋‚˜ ๋” ํ™•์ธํ•ด๋ด…์‹œ๋‹ค! (์ถœ์ฒ˜: JSConf)

const button = document.getElementById('run');

button.addEventListener('click', () => {
  Promise.resolve().then(() => {
    console.log('MicroTask 1');
  });
  console.log('Listener 1');
});
button.addEventListener('click', () => {
  Promise.resolve().then(() => {
    console.log('MicroTask 2');
  });
  console.log('Listener 2');
});
  • ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ ์ฝ˜์†” ์ฐฝ์—๋Š” ์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ€ ์ถœ๋ ฅ๋ ๊นŒ์š”? Listener 1 MicroTask 1 Listener 2 MicroTask 2

์ถœ๋ ฅ์ด ์ง๊ด€์ ์ด์ง€ ์•Š์œผ๋ฏ€๋กœ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค!

  1. ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ๋ฒ„ํŠผ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  2. ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฒซ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  3. Promise๊ฐ€ resolve๋˜๊ณ  ์ฝœ๋ฐฑ์ด ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„ Listener 1 ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  4. ์ฒซ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์—์„œ ์ œ๊ฑฐ๋˜๊ณ  ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ์˜ ์ž‘์—…์ด ํ˜ธ์ถœ ์Šคํƒ์œผ๋กœ ๋„˜์–ด์™€ MicroTask 1 ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  5. ๋‘ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋„ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
  6. ์‹คํ–‰์ด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ JS์˜ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ๋Š” ๋ฌด์—‡์ผ๊นŒ์š”?

  1. Promises
  2. Mutation Observers
  3. queueMicrotask()

Queue ์ •๋ฆฌํ•˜๊ธฐ

  • Task Queue
    • ์ž‘์—…์ด ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
    • ์ด๋™ ์ „ ๋ชจ๋“  ์ž‘์—…์ด ์™„๋ฃŒ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ทœ์น™์€ ์—†์Šต๋‹ˆ๋‹ค.
  • Render Queue
    • ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ๋ Œ๋” ํ์— ์˜ค๋ฉด ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์™„๋ฃŒํ•˜๊ณ  ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์‹œ์ž‘๋œ ํ›„ ์ž‘์—…์ด ์ถ”๊ฐ€๋˜๋ฉด ํ•ด๋‹น ์ž‘์—…์€ ๋‹ค์Œ ์ฐจ๋ก€๋กœ ๋„˜๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • Microtask Queue
    • ํ•ด๋‹น ํ๋Š” ๋ชจ๋“  ์ž‘์—…์ด ์—†์–ด์งˆ ๋•Œ๊นŒ์ง€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— Promise๊ฐ€ ๋ฌดํ•œ ์žฌ๊ท€๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  Queue๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์˜ˆ์‹œ

function log(arg) {
  console.log(arg);
}

// Function which will add a callback to task queue using setTimeout
function taskQueue(number, callback) {
  setTimeout(function () {
    callback(`Timeout ${number}`);
  }, 0);
}

// Function which will return a promise
function microTaskQueue(number) {
  return Promise.resolve(`Promise ${number}`);
}

// Pushing to microtask queue
microTaskQueue(1).then(log);
microTaskQueue(2).then(log);

// Pushing to task queue
taskQueue(1, log);

// Pushing to render queue
requestAnimationFrame(function () {
  log('RequestAnimationFrame 1');
});

//Normal code to show that the script will run till completion first
for (let i = 0; i < 100000000; i++) {}
console.log('The end');

์ˆœ์„œ๋ฅผ ์ดํ•ดํ•ด๋ด…์‹œ๋‹ค!

  1. ๋จผ์ € microTaskQueue(1).then(log) / microTaskQueue(2).then(log) ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋‘ log ํ•จ์ˆ˜๋Š” ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์— ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.
  2. setTimeout API๋ฅผ ํ†ตํ•ด ํƒœ์Šคํฌ ํ์— log ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” taskQueue(1, log) ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ Œ๋” ํ์— log ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” requestAnimationFrame() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  4. for๋ฌธ์ด ์‹คํ–‰๋˜๊ณ  The end ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  5. ์ด์ œ ํ˜ธ์ถœ ์Šคํƒ์ด ๋น„์—ˆ์œผ๋ฏ€๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  6. ์ฒซ ๋ฒˆ์งธ๋Š” ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ๊ฐ€ ๊ฐ€์žฅ ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’์œผ๋ฏ€๋กœ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์˜ log ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด Promise 1 , Promise 2 ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  7. ๊ทธ ๋‹ค์Œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ Œ๋” ํ๋กœ ์ด๋™ํ•˜์—ฌ RequestAnimationFrame 1์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.
  8. ๋งˆ์ง€๋ง‰์œผ๋กœ ํƒœ์Šคํฌ ํ๋กœ ์ด๋™ํ•˜์—ฌ Timeout 1 ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•ด๋ณด์ž๋ฉด ์•„๋ž˜์™€ ๋น„์Šทํ•  ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

์ถœ์ฒ˜: JSConf

์ด ์ด์•ผ๊ธฐ๋ฅผ ๋“ฃ๊ณ  ๋” ๊ถ๊ธˆํ•œ ์ ์ด ์ƒ๊ฒผ๋‹ค๋ฉดโ€ฆ

https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

์œ„ ๋ธ”๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜์—ฌ ํ์˜ ๋™์ž‘์ด ๋ธŒ๋ผ์šฐ์ €๋งˆ๋‹ค ์–ด๋–ป๊ฒŒ ์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ†ตํ•ด ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

์ฐธ๊ณ  ์ž๋ฃŒ