Microtask Queue
Do not use setInterval for animation!
1. Event Loop ๐ฉโ๐ป
ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ์ค๋ ๋ ์ต์ ํ๋ฅผ ์ํด ๋น๋๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋ API ๊ฐ ์กด์ฌํ๋ค. Swift ๊ฐ์ ๊ฒฝ์ฐ๋ GCD, Run Loop ์ ๊ฐ์ ๊ฒ๋ค์ด ์ด๋ฐ ์ญํ ์ ํ๋๋ฐ, ์ด ๊ฒฝ์ฐ ๋ฉํฐ์ฝ์ด ํ๊ฒฝ์์ ์ค๋ ๋ ์์์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
ํ์ง๋ง JavaScript ์ ์ด๋ฒคํธ ๋ฃจํ๋ ์กฐ๊ธ ๋ค๋ฅด๋ค. ๋น๋๊ธฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํจ์ ๋ง์ง๋ง, ๊ฐ์ฅ ๊ฒฐ์ ์ ์ธ ์ด์ ๋ ์ฑ๊ธ์ค๋ ๋ ํ๊ฒฝ์ผ๋ก ์ธํ ์ฝ๋ ๋ธ๋กํน์ ๋ง๊ธฐ ์ํด ๋ฐ๋์ ํ์ํ๋ค. JavaScript ์์๋ ์ด๋ฒคํธ ๋ฃจํ๊ฐ ์์ผ๋ฉด ์ฝ๋์ ์คํ์ด ๋ฉ์ถฐ๋ฒ๋ฆฐ๋ค!
๊ทธ๋ฆฌ๊ณ ์ด ์ด๋ฒคํธ ๋ฃจํ์์ ๋น๋๊ธฐ ์ด๋ฒคํธ๋ฅผ ๋ณด๊ดํ๋ Task Queue ๋ ์ฐ์ ์์์ ๋ฐ๋ผ Macrotask Queue ์ Microtask Queue ๋ก ๋๋๋ค.
์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ์์ ์ด ์คํ๋๋ ์์๋
- Synchronous Task
- Asynchronous Task
- Microtask Queue:
process.nextTick()
,Promise callback
,async functions
,queueMicrotask()
- MacroTask Queue:
setTimeout()
,setInterval()
,addEventListener()
- Microtask Queue:
์ ๊ฐ๋ค.
2. Macrotask Queue ๐ฉโ๐ป
Macrotask Queue ๋๋ ๊ทธ๋ฅ Task Queue ๋ผ๊ณ ๋ถ๋ฆฌ๋ ์ด๊ฒ์ setTimeout()
, setInterval()
, addEventListener()
์
๊ฐ์ ๊ฒ๋ค์ด ์ถ๊ฐ๋๋ค.
function getData() {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((response) => response.json())
.then(({ title }) => console.log(`Task 2: ${title}`));
}
function handleHeavyTask(bFetch) {
if (bFetch) getData();
else console.log('Task 2: ์ง์ฐ ์์ด ์คํ!');
}
(function () {
console.log('Task 1');
handleHeavyTask(false);
console.log('Task 3');
})();
Task 1
Task 2: ์ง์ฐ ์์ด ์คํ!
Task 3
Task 2 ๊ฐ Synchronous Task ์ด๋ฏ๋ก Task 1 > Task 2 > Task 3 ์์๋๋ก ์คํ๋๋ค.
์ด๋ฒ์๋ handleHeavyTask ์ arguments ๋ก true
๋ฅผ ๋ฃ์ด๋ณด์.
(function () {
console.log('Task 1');
handleHeavyTask(true);
console.log('Task 3');
})();
Task 1
Task 3
Task 2: delectus aut autem
Task 2 ๊ฐ Asynchronous Task ์ด๋ฏ๋ก Task 1 > Task 3 > Task 2 ์์๋๋ก ์คํ๋์๋ค. Task 2 ๊ฐ Task Queue ์ ์์ฌ ๋๊ธฐ๋๊ณ ์๋ค ์๋ต์ด ์ค๊ณ stack ์ด ๋น ๋๋ฅผ ๊ธฐ๋ค๋ ธ๋ค ์คํ๋๊ธฐ ๋๋ฌธ์ด๋ค.
์์ ๊ฐ์ด ๋๊ธฐ
์ฝ๋์ ๋น๋๊ธฐ
์ฝ๋๊ฐ ์์ด๋ฉด ์์๋ฅผ ์์ธกํ๊ธฐ ํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ์ผ์ผํ ํจ์๋ฅผ ๋ฐ๋ผ๊ฐ์ ์ ์ฒด ์ฝ๋๋ฅผ ๋ด์ผ ํ๊ธฐ
๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ์ด๋ฐ ๋ฌธ์ ๋ฅผ ๊ฐ์ฅ ์ฝ๊ฒ ํด๊ฒฐํ ์ ์๋ ๋ฐฉ๋ฒ์ handleHeavyTask()
ํจ์๊ฐ ํญ์ ๋น๋๊ธฐ๋ก ์๋ํ๋๋ก ํ๋ ๊ฒ์ด๋ค.
function handleHeavyTask(bFetch) {
if (bFetch) getData();
else setTimeout(() => console.log('Task 2: ์ง์ฐ ์์ด ์คํ!'));
}
์ด์ arguments ๋ก false
๋ฅผ ์
๋ ฅํด๋ ์คํ ์์๊ฐ Task 1 > Task 3 > Task 2
๋ก ๋ณด์ฅ๋๋ค.
Task 1
Task 3
Task 2: ์ง์ฐ ์์ด ์คํ!
3. Microtask Queue ๐ฉโ๐ป
๊ทธ๋ฐ๋ฐ ์ฌ๋ฌ ๊ฐ์ ๋น๋๊ธฐ ์ฝ๋๊ฐ ์กด์ฌํ ๋ ์ฐ์ ์์๋ ์ด๋ป๊ฒ ๋ ๊น? ์ฐ์ , ๋น๋๊ธฐ ์ฝ๋ฐฑ์ด Queue ์ ๋ค์ด๊ฐ๋ ์์์ stack ์ด ๋น์์ ธ ์๋์ง๊ฐ ์ค์ํ๋ค.
console.log('Task 1');
setTimeout(() => console.log('Task 2'));
console.log('Task 3');
setTimeout(() => console.log('Task 4'));
console.log('Task 5');
์ ์ฝ๋๋ ๋๊ธฐ ์ฝ๋ Task 1, Task 3, Task 5 ๊ฐ ์คํ๋๋ ๋์ ๋น๋๊ธฐ ์ฝ๋ Task 2 ์ Task 4 ๋ ์ฆ๊ฐ ์ฝ๋ฐฑ์ Queue ์ ๋๊ธฐ์ํจ๋ค. ๋ฐ๋ผ์ ์คํ ์์๋ Task 1 > Task 3 > Task 5 > Task 2 > Task 4 ๊ฐ ๋๋ค.
๊ทธ๋ฐ๋ฐ Task 2 ๊ฐ Task 4 ๋ณด๋ค ๋ ๋ฌด๊ฒ๋ค๊ณ ํด๋ณด์.
console.log('Task 1');
setTimeout(() => console.log('Task 2'), 2);
console.log('Task 3');
setTimeout(() => console.log('Task 4'), 1);
console.log('Task 5');
๊ทธ๋ฌ๋ฉด ๋๊ธฐ ์ฝ๋๊ฐ ์คํ๋๋ ๋์ ๋น๋๊ธฐ ์ฝ๋ Task 4 ๊ฐ ๋จผ์ Queue ์ ์ถ๊ฐ๋์ด ๋๊ธฐํ๊ณ , ์ดํ Task 2 ๊ฐ Queue ์ ์ถ๊ฐ๋๋ค. ๋ฐ๋ผ์ ์คํ ์์๋ Task 1 > Task 3 > Task 5 > Task 4 > Task 2 ๊ฐ ๋๋ค.
๊ทธ๋ฐ๋ฐ ๋๊ธฐ ์ฝ๋๊ฐ ๋ฌด๊ฑฐ์ stack ์ ์ค๋ ์๊ฐ ์ ์ ํด Task Queue ์ ์ฌ๋ฌ ๊ฐ์ ๋น๋๊ธฐ ์ฝ๋๊ฐ ์์ฌ ์คํ์ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ค๊ณ ํด๋ณด์.
console.log('Task 1');
setTimeout(() => console.log('Task 2'));
console.log('Task 3');
setTimeout(() => console.log('Task 4 important!'));
console.log('Task 5');
Task 1
Task 3
Task 5
Task 2
Task 4 important!
Task 2 ์ Task 4 ๊ฐ ๋น๋๊ธฐ ์ฝ๋์ธ๋ฐ Task 4 ๊ฐ ๋ ์ค์ํด ๋จผ์ ์คํ๋๊ธฐ๋ฅผ ์ํ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น? Task 2 ๋ณด๋ค Task 4 ๊ฐ Task Queue ์ ๋จผ์ ์ถ๊ฐ๋๋๋ก ์ฝ๋๋ฅผ ์์ ํด์ฃผ์ด์ผํ๋ค. ํ์ง๋ง ์ ๊ฒฝ์ฐ๋ ๋น๋๊ธฐ ์ฝ๋ฐฑ์ด ์ฆ์ Queue ์ ์ถ๊ฐ๋๊ธฐ ๋๋ฌธ์ ์์ธก์ด ๊ฐ๋ฅํ์ง๋ง, ์ค์ ์ฝ๋์์๋ ์์ธก์ด ๋ถ๊ฐ๋ฅํ ์ํฉ์ด ๋ฐ์ํ๋ค.
์ด๋ฅผ ์ํด์ Task Queue ์ ์ฌ๋ฌ๊ฐ์ ๋น๋๊ธฐ ์ฝ๋ฐฑ์ด ์์์ ๋ ๋น๊ต์ ์ฐ์ ์์๊ฐ ๋์ ์ฝ๋ฐฑ๊ณผ ๋ฎ์ ์ฝ๋ฐฑ์ ๊ตฌ๋ถํ๊ธฐ ์ํด Task Queue ๋ฅผ
2๊ฐ๋ก ๋๋์ด ๊ด๋ฆฌํ๋ค. ์ฐ์ ์์๊ฐ ๋์ ์ด๊ฒ์ Microtask Queue ๋ผ ๋ถ๋ฆฌ๋ ์ด๊ฒ์
process.nextTick()
, Promise callback
, async functions
, queueMicrotask()
์ ๊ฐ์ ๊ฒ๋ค์ด ์ถ๊ฐ๋๋ค.
console.log('Task 1');
setTimeout(() => console.log('Task 2'));
console.log('Task 3');
queueMicrotask(() => console.log('Task 4 important!'));
console.log('Task 5');
console.log('Task 1');
setTimeout(() => console.log('Task 2'));
console.log('Task 3');
Promise.resolve().then(() => console.log('Task 4 important!'));
console.log('Task 5');
Task 1
Task 3
Task 5
Task 4 important!
Task 2
Task Queue ์ Task 2 ๊ฐ ๋จผ์ ๋ฑ๋ก๋์์ง๋ง Task 4 ๊ฐ Microtask Queue ๋ก ๋ฑ๋ก๋์ด ์คํ ์์๋ Task 1 > Task 3 > Task 5 > Task 4 > Task 2 ๊ฐ ๋๋ค.
Reference
- โUsing microtasks in JavaScript with queueMicrotask().โ MDN Web Docs. Apr. 06, 2024, accessed Apr. 27, 2024, MDN - microtasks.
- โ๋ ๊ฐ์ queue ๋ก ๋์์ฑ ์ ์ด.โ Youtube. Sep. 02, 2023, ๋ ๊ฐ์ queue ๋ก ๋์์ฑ ์ ์ด.