[JavaScript] ์ฝ์คํ, ์ฝ๋ฐฑํ, ์ด๋ฒคํธ ๋ฃจํ์ ๋์ ์๋ฆฌ๋ฅผ ํตํ ๋น๋๊ธฐ ํจ์์ ์คํ ๊ณผ์
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋น์ฐํ ์์ฌ ์์ด ์ฌ์ฉํ๋ ๋น๋๊ธฐ ํจ์ ์คํ ๊ณผ์ ์ ๋ค์ฌ๋ค๋ณผ ๊ธฐํ๊ฐ ์๊ฒผ๋ค. ์ฑ๊ธ ์ค๋ ๋ ์ธ์ด์ธ ์๋ฐ์คํฌ๋ฆฝํธ๋ ํ ์ค ํ ์ค ์์๋๋ก ๋๊ธฐ์ ์ผ๋ก ์คํ๋์ด์ผ ํ๋ฉฐ, ๋ ๊ฐ์ง ์ด์์ ํ์คํฌ๋ฅผ ๋ณ๋ ฌ์ ์ผ๋ก ์ํํ ์ ์์ด์ผ ํ๋๋ฐ, setTimeout
์ด๋ ์น API, ES6์ promise
๊ฐ์ ๋น๋๊ธฐ ์ฝ๋ฐฑ์ ์ด๋ป๊ฒ ์คํ๋๊ณ ์๋ ๊ฒ์ผ๊น?
์ฐ์ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ ๊ฐ์ง ์ด์์ statements๊ฐ ๋ณ๋ ฌ์ ์ผ๋ก ์คํ๋์ง ๋ชปํ๋ ๊ฒ์ ๋ง๋ค. ์คํ์ ํญ์ ๋๊ธฐ์ ์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ ์์ง V8์ ํ๋ก๊ทธ๋จ ๋ด ๋ชจ๋ ๋ณ์์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ด ์ผ์ด๋๋ Memory Heap๊ณผ ์คํ ํ๋ ์์ด ์์ด๋ ์ฝ ์คํ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์๊ณ ์ด ์ฝ ์คํ(ํธ์ถ ์คํ)์ด ํ๋์ด๋ฏ๋ก ์ฑ๊ธ ์ค๋ ๋์ด๋ค. ํ์ง๋ง, ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋๋ ๋ธ๋ผ์ฐ์ ๋ Node.js ๊ฐ์ ํ๊ฒฝ์์๋ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๊ฐ ํ์ฉ๋๋ค. ์ด๋ฅผ ์ํธ ์ฐ๊ณํด์ฃผ๋ ์ญํ ์ ์ด๋ฒคํธ ๋ฃจํ๊ฐ ๋ด๋นํ๋ค.
console.log('Message 1');
setTimeout(function() {
console.log('Message 2')
}, 100);
console.log('Message 3')
// output
// 'Message 1'
// 'Message 3'
// 'Message 2'
setTimeout
์ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์ ์ฝ๋ฐฑ ํจ์๊ฐ ์ค๊ณ , ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์ ๋ฐ๋ฆฌ ์ธ์ปจ๋ ๋จ์์ ์๊ฐ์ด ์ค๊ธฐ ๋๋ฌธ์, ํน์ ์๊ฐ ์ดํ์ ์คํ๋๋ ํน์ฑ ์ 'Message 2'์ด ๊ฐ์ฅ ๋ง์ง๋ง์ ์ถ๋ ฅ๋๋ค.
์ฌ๊ธฐ์ event loop์ ๋์์ด ์์๋ค. ์ด๋ฒคํธ ๋ฃจํ ๋๋ถ์ ๋ชจ๋ ๋๊ธฐ์ ์ธ ์ฝ๋๊ฐ ์คํ์ด ๋๋ ๋ค์์ผ ๋น๋๊ธฐ์ ์ฝ๋๊ฐ ์คํ๋ ์ ์๋ค. ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์ดํดํ๊ธฐ ์ํด์๋ ์ฝ ์คํ์ ๋จผ์ ์์์ผ ํ๋ค.
์ฝ ์คํ(Call Stack)์ด๋?
์ฝ ์คํ์ ์ธํฐํ๋ฆฌํฐ๊ฐ ํ๋ก๊ทธ๋จ์ ์ฝ์ ๋ ํ๋์ฉ ์์ฌ๋ค์ด๊ฐ๊ณ , ์คํ๋๋ฉฐ, ์คํ์ด ์๋ฃ๋๋ฉด ๋น์์ง๋ ๊ณณ์ด๋ค. ํธ์ถ๋ ์์์ ๋ฐ๋๋ก ์คํ์ด ๋๋ ๊ตฌ์กฐ๋ผ '์คํ'์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. ๊ฐ๋ฐ์์ ์ค์๋ก ์ฌ๊ท ํจ์ ๋ฑ์ ์ผ์ ๋ ์ฝ์คํ์ ์ฌ๋ผ๊ฐ ํจ์๊ฐ ๋ ์๊ธฐ ์์ ์ ๋ถ๋ฌ ์คํ์ ์ฑ์ฐ๊ณ .. ์ ์ ๋ธ๋ผ์ฐ์ ๋ณ ์ต๋ ํธ์ถ ์คํ์ ์ด๊ณผํ ๊ฒฝ์ฐ Uncaught RangeError: Maximum call stack size exceeded
๊ฐ์ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๋ณผ ์ ์๋๋ฐ, ๊ทธ๋ ๋ฑ์ฅํ๋ call stack์ด๋ค.
๋ง์ผ ์คํํ๋ ์ฝ๋๊ฐ ๋น๋๊ธฐ์ ์ด๋ผ๊ณ ํ ๋(setTimeout
, promise
, click event
๋ฑ), ์ฝ๋๋ ์ด๋ฒคํธ ํ
์ด๋ธ๋ก ํฅํ๊ณ , ์ด ํ
์ด๋ธ์ ์ง์ ๋ ์๊ฐ ์ดํ์ ๋น๋๊ธฐ ์ฝ๋๋ฅผ ์ฝ๋ฐฑ/์ด๋ฒคํธ ํ
๋ก ์ฎ๊ธฐ๋ ์ญํ ์ ํ๋ค.
์ฝ๋ฐฑ ํ(Callback Queue)๋?
์ฝ๋ฐฑ ํ๋ ์์ ๋งํ ๊ฒ์ฒ๋ผ ๋น๋๊ธฐ ์ฝ๋๊ฐ ๋ค์ด๊ฐ๊ณ , ์คํ์ ์ํด ๋๊ธฐํ๋ ๊ณณ์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๊ฐ ์คํ ์ค์ ์ด๋ฒคํธ๋ฅผ ๋ง๋๋ฉด ํด๋น ์ด๋ฒคํธ๋ค์ ์ฐจ๊ณก ์ฐจ๊ณก ์ฝ๋ฐฑ ํ์ ์์ธ๋ค. ์คํ๊ณผ ๋ค๋ฅด๊ฒ ํ์ด๋ฏ๋ก, ์ ์ ์ ์ถ๋๋ค๋ ํน์ง์ด ์๋ค.
์ด๋ฒคํธ ๋ฃจํ(Event Loop)๋?
๊ทธ๋ฐ ๋ค์์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๊ณตํ๋ ์ด๋ฒคํธ ๋ฃจํ๊ฐ ๋ฑ์ฅํ๋ค. ์ด๋ฒคํธ ๋ฃจํ๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ ธ๋์์ ์ฌ์ฉ๋๋ค. ์ด๋ฒคํธ ๋ฃจํ๋ ๊ณ์ ๋์๊ฐ๋ฉด์ ๋ฉ์ธ ์คํ์ ๋ณด๋ฉฐ ๋ง์ผ ์คํํ ๊ฒ ํ๋๋ผ๋ ์๋์ง ๋ณด๊ณ , ์๋ค๋ฉด ์ฝ๋ฐฑ ํ๋ฅผ ํ์ธํ ๋ค ์ฝ๋ฐฑ ํ์ ์คํํ ์ฝ๋๊ฐ ์๋ค๋ฉด ๊ทธ ์์์ ๊ทธ๊ฑธ ๊บผ๋ด๋ค์ด์ ๋ฉ์ธ ์คํ์ ์คํ์ ์ํด ์ฌ๋ ค๋๋ ์ญํ ์ ํ๋ค. ์ด ํ ๋ฒ์ ๊ณผ์ ์ tick์ด๋ผ๊ณ ํ๋ค. ์ด๋ฒคํธ ๋ฃจํ๋ ์ด ์์ ์ ๊ณ์ ์งํํด looping ํ๋ค.
Job Queue
์ฝ๋ฐฑ ํ๋ฟ๋ง ์๋๋ผ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๊ณตํ๋ ๋ ๋ค๋ฅธ ํ๋ก๋ ์ก ํ๊ฐ ์๋ค. new Promise()
๊ธฐ๋ฅ์ ์ํด์๋ง ์กด์ฌํ๋ค. ์ฝ๋ ๋ด์ promise
๋ฅผ ์ฌ์ฉํ ๋, ์ฝ๋ฐฑ ๋ฉ์๋์ธ then()
๋ฅผ ์ถ๊ฐํ๋ฉด, ์ด 'thenable'ํ ๋ฉ์๋๋ promise
๊ฐ ๋ฆฌํด๋๊ฑฐ๋ resolve
๋์์ ๋ job queue์ ์ถ๊ฐ๋๊ณ , ๊ทธ ํ์ ์คํ์ด ๋๋ค.
console.log('Message no. 1: Sync');
setTimeout(function() {
console.log('Message no. 2: setTimeout');
}, 0);
const promise = new Promise(function(resolve, reject) {
resolve();
});
promise
.then(function(resolve) {
console.log('Message no. 3: 1st Promise');
}).then(function(resolve) {
console.log('Message no. 4: 2nd Promise');
});
console.log('Message no. 5: Sync');
// Message no. 1: Sync
// Message no. 5: Sync
// Message no. 3: 1st Promise
// Message no. 4: 2nd Promise
// Message no. 2: setTimeout
ํํ setTimeout์ด ๋จผ์ ์ฝ๋ฐฑ ํ๋ก ๋ค์ด๊ฐ๊ณ , ๊ทธ ํ promise์ thenableํ ๋ฉ์๋๊ฐ ๋ค์ด์ ๊ฑฐ๋ผ ์๊ฐํ์ง๋ง, ์กํ๊ฐ ์ฝ๋ฐฑ์ ์คํํ๋ ๋ฐ ์์ด ๋์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ ์ด๋ฒคํธ ๋ฃจํ๋ ์กํ์ ์๋ ๋ชจ๋ ํ์คํฌ๋ฅผ ์๋ฃํ ์ดํ์ ์ฝ๋ฐฑ ํ๋ก ๋์ด๊ฐ๋๋ก ๋์ด ์๋ค. ๋ฐ๋ผ์ ํ๋ก๋ฏธ์ค๋ฅผ ์ํ ๋ชจ๋ thenable
์ฝ๋ฐฑ์ด ๋จผ์ ๋ถ๋ฆฌ๊ณ , ๊ทธ ํ์ setTimeout
์ฝ๋ฐฑ์ด ๋ถ๋ฆฐ๋ค.
setTimeout
์ ๋ ๋ฒ์งธ ์ธ์๊ฐ 0์ด๋ผ๊ณ ํด๋ ์ผ๋จ ๋น๋๊ธฐ ํจ์์ด๋ฏ๋ก ์ฝ๋ฐฑ ํ์ ๋๊ธฐํ๋ ์ํฉ์ด ๋ฐ์ํ๋ค. ๊ทธ๋์ Message 1
์ดํ์ ๋ฐ๋ก Message 2
๊ฐ ์ฐํ์ง ์๋๋ค.