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
- Global Execution Context(GEC)๊ฐ ์์ฑ๋์ด ํธ์ถ ์คํ์ ํธ์๋ฉ๋๋ค.
- foo ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค.
- foo()์ ๋ํ ์คํ ์ปจํ ์คํธ๊ฐ ์์ฑ๋๊ณ ํธ์ถ ์คํ์ ํธ์๋ ๋ค ํ ์ค์ฉ ์คํํฉ๋๋ค.
- foo() ํจ์์์ โfooโ๋ฅผ ์ฝ์์ ์ถ๋ ฅํ๊ณ jazz() ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
- jazz()์ ๋ํ ์คํ ์ปจํ ์คํธ๊ฐ ์๋ก ์์ฑ๋๊ณ ํธ์ถ ์คํ์ ์๋จ์ ํธ์๋ฉ๋๋ค.
- jazz()๋ โjazzโ๋ฅผ ์ฝ์์ ์ถ๋ ฅํ๊ณ bar() ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
- bar()์ ๋ํ ์คํ ์ปจํ ์คํธ๊ฐ ์๋ก ์์ฑ๋๊ณ ํธ์ถ ์คํ์ ์๋จ์ ํธ์๋ฉ๋๋ค. ๊ทธ ์ดํ โbarโ๊ฐ ์ฝ์์ ์ถ๋ ฅ๋ฉ๋๋ค.
- bar()๊ฐ ๋ฆฌํด๋๋ฉด ์คํ์์ ์ ๊ฑฐ(pop)๋ฉ๋๋ค.
- jazz()์ foo()๋ชจ๋ ์ ๊ฑฐ๋์ด ์คํ์ ๋ง์ง๋ง์ ๋๋ฌํ๊ฒ ๋ฉ๋๋ค.
- ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋๋ฉด 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++)๋ก ๊ตฌํ๋์ง๋ง ์ผ๋ฐ์ ์ผ๋ก ์๋ฐ์คํฌ๋ฆฝํธ์ ํจ๊ป ์ฌ์ฉ๋ฉ๋๋ค.
- ๋คํธ์ํฌ ์์ฒญ
- DOM ์กฐ์
- Local Storage
- ๋ธ๋ฃจํฌ์ค
- ํ๋ฉด ์บก์ฒ
- ์์น
- 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
- Task Queue (= Callback Queue)
- Render Queue
- 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์ ์งํํ ์์ ์ด ์๋์ง ํ์ธํ๊ณ ํธ์ถ ์คํ์ ํธ์ํ์ฌ ์คํํ๊ฒ ๋ฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ํ๋ก๊ทธ๋จ์ ์๋์ ๊ฐ์ ์์๋ก ์งํ์ด ๋๋ ๊ฒ์ด์ฃ !
- ํธ์ถ ์คํ์ด Web API ๊ด๋ จ๋ ์์ ์ ๋ง๋๋ฉด Web API์๊ฒ ๋์์ ์์ฒญํฉ๋๋ค.
- Web API๋ ํธ์ถ ์คํ์ ์๋ฃ๋ก ํ์ํ ๋ค Web API๋ก ํด๋น ์์ ์ ๋๊น๋๋ค.
- ๋ธ๋ผ์ฐ์ ๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์์ ์ ์คํํ๊ณ ์ฝ๋ฐฑ์ Task Queue(Callback Queue)๋ก ํธ์ํฉ๋๋ค.
- ์ผ๋ฐ ์ฝ๋ ์คํ์ด ์๋ฃ๋ ๋ค ํธ์ถ ์คํ์ด ๋น์ด ์์ผ๋ฉฐ GEC๋ ์ ๊ฑฐ๋๋ฉด ์ด๋ฒคํธ ๋ฃจํ๊ฐ ์ผ์ ์์ํฉ๋๋ค.
- ์ด๋ฒคํธ ๋ฃจํ๋ Task Queue์ ์์ ์ ํ์ธํ๊ณ ์์ ์ ํ๋์ฉ Call Stack์ ํธ์ํ ๋ค ์คํํฉ๋๋ค.
- 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์ด๋ผ๊ณ ๋ช ์๋์ด ์์ต๋๋ค. ๊ทธ ์ธ๋ ํญ๋ฐํ๋ ํ๋ก๊ทธ๋จ๊ณผ ๋์ผํ ํ๋ก๊ทธ๋จ์ ๋๋ค. ์๋๋ฐฉ์์ ์ดํดํด๋ด ์๋ค!
- GEC๊ฐ ์์ฑ๋์ด ํธ์ถ ์คํ์ ์ถ๊ฐ๋ฉ๋๋ค.
- ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค.
- foo() ํจ์ ์ปจํ ์คํธ๊ฐ ํธ์ถ ์คํ์ ์ถ๊ฐ๋ฉ๋๋ค.
- foo()๊ฐ ์คํ๋๊ณ ์ฒซ ๋ฒ์งธ ํธ์ถ์์ i๊ฐ์ 0์ผ๋ก ์ถ๋ ฅํฉ๋๋ค.
- Web API์ธ setTimeout์ ๋ง๋๋ฉด ํธ์ถ ์คํ์์ Web API ์ชฝ์ธ ๋ธ๋ผ์ฐ์ ์๊ฒ ์์ ์ ๋๊น๋๋ค.
- foo() ํจ์์ ๋ง์ง๋ง์ ๋๋ฌํ์ฌ foo() ์คํ ์ปจํ ์คํธ๊ฐ ์ฌ๋ผ์ง์ง๋ง ์ฌ์ ํ setTimeout์ด ์คํ๋์ง ์์ ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋์ง ์์ต๋๋ค.
- ์ง์ฐ ์๊ฐ์ด 0์ด๊ธฐ์ setTimeout์ ์ฝ๋ฐฑ์ด Task Queue์๊ฒ ์ ๋ฌ๋ฉ๋๋ค.
- foo(i+1)์ธ Task Queue์ ํจ์๋ ์ด๋ฒคํธ ๋ฃจํ์ ์ํด ๋น ํธ์ถ ์คํ์ผ๋ก ํธ์๋๊ณ ์คํํฉ๋๋ค.
- 3๋จ๊ณ๋ก ๋ค์ ๋์๊ฐ ์คํํฉ๋๋ค.
์์ ์ ๊ณ์ ์คํํ๋ฉฐ ํธ์ถ ์คํ์ ์ฑ์ฐ์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ ๋ชจ๋ ๋ธ๋ผ์ฐ์ ์์ ์ ๊ณตํ๋ setTimeout() API ๋๋ถ์ ๋๋คโฆ!
ํ์์์ ์ ๋ ฌ(Timeout Sort!!!)
๋ฒ๋ธ ์ ๋ ฌ, ์ฝ์ ์ ๋ ฌ, ์ ํ ์ ๋ ฌ์ ๋ํด ๋ค์ด๋ณด์ จ๊ฒ ์ง๋ง ํ์์์ ์ ๋ ฌ์ ๋ํด ์๊ณ ๊ณ์ ๊ฐ์?
setTimeout() API๋ฅผ ์ด์ฉํ์ฌ ์ซ์๋ฅผ ์ ๋ ฌํด๋ณด๊ฒ ์ต๋๋ค.
let arr = [10, 100, 500, 20, 35];
arr.forEach((item) => {
setTimeout(() => console.log(item), item);
});
- ํญ์ GEC๊ฐ ์์ฑ๋ฉ๋๋ค.
- ๋ชจ๋ ๋ฐฐ์ด ์์๋ setTimeout๋ฅผ ํธ์ถ๋์ด ์คํ์ ํธ์๋ ํ ๋ธ๋ผ์ฐ์ ๋ก ์คํ๋ก๋ ๋ฉ๋๋ค.(๋๊น๋๋ค.)
- setTimeout์ ๋ฐฐ์ด์ ์ ์๋ ์ซ์๋งํผ ์ง์ฐ๋ฉ๋๋ค.
- ๊ฐ์ฅ ์งง์ 10ms๊ฐ ๋๋๋ฉด Task Queue๋ก ํธ์๋๊ณ ์ด๋ฒคํธ ๋ฃจํ๋ก ์ธํด ์ฝ ์คํ์ผ๋ก ํธ์๋๊ณ 10์ด ๊ธฐ๋ก๋ฉ๋๋ค.
- ์ดํ 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๊ฐ์ง ์ํ๊ฐ ์์ต๋๋ค.
- Resolved, ์์ ์ด ์๋ฃ๋ ์ํ๋ฅผ ์๋ฏธํฉ๋๋ค.
- Rejected, ์์ ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ํ๋ฅผ ์๋ฏธํฉ๋๋ค.
- 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์ธ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ชจ๋ ์์ ์ด ์ผ๊ฒ ๋ฉ๋๋ค. ์๋ ์์๋ฅผ ํตํด ์ด์ ๋ฅผ ์์๋ด ์๋ค.
- ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋๊ณ btn์ click ์ด๋ฒคํธ๊ฐ ์ถ๊ฐ๋ฉ๋๋ค.
- id๊ฐ kill์ธ ๋ฒํผ์ ๋๋ฆ ๋๋ค.
- ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ํธ์ถ๋๊ณ ํ์
blockEventLoop
ํจ์๊ฐ ์ถ๊ฐ๋ฉ๋๋ค. - ํธ์ถ ์คํ์ ๋น์ด์๋ ์ํ์ด๋ฏ๋ก ์ด๋ฒคํธ ๋ฃจํ๊ฐ promise๋ฅผ ํธ์ถ ์คํ์ผ๋ก ๊ฐ์ ธ์ค๊ณ ์คํํ๋ ๋์ ๋ค๋ฅธ promise๊ฐ ํ์ ์ถ๊ฐ๋๋ ์์ ์ด ๋ฐ๋ณต๋ฉ๋๋ค.
- ๊ทธ๋ ๊ธฐ์ ๋ฉ์ธ ์ค๋ ๋๋ ์ฌ์ง ์๊ณ ์ผํ๋ฉฐ ์ด๋ก ์ธํด ์ ์ง๋ ํ๋ฉด์ผ๋ก ๋ณด์ด๊ฒ ๋ฉ๋๋ค.
๋ค๋ฅธ ์์๋ฅผ ํ๋ ๋ ํ์ธํด๋ด ์๋ค! (์ถ์ฒ: 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
์ถ๋ ฅ์ด ์ง๊ด์ ์ด์ง ์์ผ๋ฏ๋ก ์คํ ์์๋ฅผ ํ์ธํด๋ด ์๋ค!
- ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ๋ฒํผ์ ์ถ๊ฐ๋ฉ๋๋ค.
- ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ฒซ ๋ฒ์งธ ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ํธ์ถ ์คํ์ ์ถ๊ฐ๋ฉ๋๋ค.
- Promise๊ฐ resolve๋๊ณ ์ฝ๋ฐฑ์ด ๋ง์ดํฌ๋กํ์คํฌ ํ๋ก ๋์ด๊ฐ๋๋ค. ๊ทธ ์ดํ
Listener 1
์ด ์ถ๋ ฅ๋ฉ๋๋ค. - ์ฒซ ๋ฒ์งธ ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ํธ์ถ ์คํ์์ ์ ๊ฑฐ๋๊ณ ํธ์ถ ์คํ์ด ๋น๊ฒ ๋ฉ๋๋ค.
๊ทธ ์ดํ ๋ง์ดํฌ๋กํ์คํฌ์ ์์
์ด ํธ์ถ ์คํ์ผ๋ก ๋์ด์
MicroTask 1
์ด ์ถ๋ ฅ๋ฉ๋๋ค. - ๋ ๋ฒ์งธ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ ๋์ผํฉ๋๋ค.
- ์คํ์ด ์ข ๋ฃ๋ฉ๋๋ค.
๊ทธ๋์ JS์ ๋ง์ดํฌ๋กํ์คํฌ๋ ๋ฌด์์ผ๊น์?
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');
์์๋ฅผ ์ดํดํด๋ด ์๋ค!
- ๋จผ์
microTaskQueue(1).then(log)
/microTaskQueue(2).then(log)
๋ฅผ ํธ์ถํฉ๋๋ค. ๋ log ํจ์๋ ๋ง์ดํฌ๋กํ์คํฌ ํ์ ๋ค์ด๊ฐ๋๋ค. - setTimeout API๋ฅผ ํตํด ํ์คํฌ ํ์ log ํจ์๋ฅผ ์ถ๊ฐํ๋
taskQueue(1, log)
๋ฅผ ํธ์ถํฉ๋๋ค. - ๋ ๋ ํ์ log ํจ์๋ฅผ ์ถ๊ฐํ๋
requestAnimationFrame()
ํจ์๋ฅผ ํธ์ถํฉ๋๋ค. - for๋ฌธ์ด ์คํ๋๊ณ
The end
๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค. - ์ด์ ํธ์ถ ์คํ์ด ๋น์์ผ๋ฏ๋ก ์ด๋ฒคํธ ๋ฃจํ๊ฐ ๋ํ๋ฉ๋๋ค.
- ์ฒซ ๋ฒ์งธ๋ ๋ง์ดํฌ๋กํ์คํฌ ํ๊ฐ ๊ฐ์ฅ ์ฐ์ ์์๊ฐ ๋์ผ๋ฏ๋ก ๋ง์ดํฌ๋กํ์คํฌ ํ์ log ํจ์๋ฅผ ํตํด
Promise 1
,Promise 2
๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค. - ๊ทธ ๋ค์ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ ๋ ํ๋ก ์ด๋ํ์ฌ
RequestAnimationFrame 1
์ด ์ถ๋ ฅ๋ฉ๋๋ค. - ๋ง์ง๋ง์ผ๋ก ํ์คํฌ ํ๋ก ์ด๋ํ์ฌ
Timeout 1
์ด ์ถ๋ ฅ๋ฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์ฝ๋๋ก ํํํด๋ณด์๋ฉด ์๋์ ๋น์ทํ ๊ฒ ์ ๋๋ค.
์ถ์ฒ: JSConf
์ด ์ด์ผ๊ธฐ๋ฅผ ๋ฃ๊ณ ๋ ๊ถ๊ธํ ์ ์ด ์๊ฒผ๋ค๋ฉดโฆ
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
์ ๋ธ๋ก๊ทธ๋ฅผ ํ์ธํ์ฌ ํ์ ๋์์ด ๋ธ๋ผ์ฐ์ ๋ง๋ค ์ด๋ป๊ฒ ์ฐจ์ด๊ฐ ์๋์ง ์ ๋๋ฉ์ด์ ์ ํตํด ํ์ธํ์ค ์ ์์ต๋๋ค!
์ฐธ๊ณ ์๋ฃ
- https://lightmap.dev/how-does-javascript-even-work-1
- https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf
- https://blog.sessionstack.com/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e
- https://joshua1988.github.io/web-development/translation/javascript/how-js-works-inside-engine/
- https://www.youtube.com/watch?v=8aGhZQkoFbQ
- https://lightmap.dev/how-does-javascript-even-work-part-2
- https://www.youtube.com/watch?v=8aGhZQkoFbQ
- https://www.youtube.com/watch?v=cCOL7MC4Pl0