
Time slicing ๊ณต๋ถ ๐
ํฐ ๋ ๋๋ง ์์ ์ ํ ๋ฒ์ ๋๊น์ง ๋ชฐ์์ ํ์ง ์๊ณ , ์๊ฒ ๋๋ ์ ์กฐ๊ธ์ฉ ์ฒ๋ฆฌํ๋ ๋ฐฉ์.
์๋ฅผ๋ค์ด ๋ธ๋ผ์ฐ์ ๊ฐ
๋ฆฌ์กํธ ๋ ๋๋ง
์ฌ์ฉ์๊ฐ ๋๋ฅธ ์ ๋ ฅ์ ๋ฐ์ํ๊ธฐ
์ฌ์ฉ์๊ฐ ์คํฌ๋กค ํ ๋ ๋ฐ์ํ๊ธฐ
์ ๋๋ฉ์ด์ ๊ทธ๋ฆฌ๊ธฐ
์ด๋ ๊ฒ ์๋ค๊ณ ํ ๋ ๋ฌด๊ฑฐ์ด ๋ ๋๋ฅผ ํ ๋ฒ์ ์ญ ํ๋ฉด ๊ทธ๋์ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ค๋ฅธ ์ผ์ ๋ชปํด์ ๋ฒ๋ฒ ์์ด ๋ฐ์ํ ์ ์๋ค.
์๋ฅผ ๋ค๋ฉด ์ด๋ ๊ฒ :
์ฌ์ฉ์๊ฐ ํด๋ฆญํจ
๊ทผ๋ฐ ์ง๊ธ ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋ฌด๊ฑฐ์ด ๋ ๋ ์์ ์ค
ํด๋ฆญ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ง๋ง ๋ฐ๋ก ์คํ ๋ชปํจ
์ ๋ ฅ์ด ๋ฒ๋ฒ ๊ฑฐ๋ฆฌ๋๊ฒ์ฒ๋ผ ๋๊ปด์ง
๊ทธ๋์ time slicing์ ์๋์ ๊ฐ์ด ๋์ํ๋ค :
๋ ๋๋ง ์์ ์กฐ๊ธ ํจ
์ค๊ฐ์ ์ ๊น ๋ฉ์ถค
๊ทธ ์ฌ์ด ๋ธ๋ผ์ฐ์ ๊ฐ ํด๋ฆญ/์คํฌ๋กค/ํ๋ฉด ์ ๋ฐ์ดํธ ์ฒ๋ฆฌ
๋ค์ ๋ ๋๋ง ์ด์ด์ ํจ
์ฆ ๊ธด ์์ ์ ์๊ฒ ์ชผ๊ฐ์ ์ฌ์ฉ์ ์ ๋ ฅ์ ๋ง์ง ์๊ฒ ๋ง๋๋ ๊ฒ.
time slicing์ ์ง์ api์ฒ๋ผ ์ฐ๋ ๊ฐ๋ ๋ณด๋ค๋ concurrent rendering์ ๋ด๋ถ ๋์ ๋ฐฉ์/ํน์ฑ์ผ๋ก ์ดํดํ๋๊ฒ ๋ ๋ง๋ค.
์ฆ time slicing์ ๋ฆฌ์กํธ๊ฐ ๋ ๋๋ง์ ์ชผ๊ฐ์ ์ค๊ฐ์ ์๋ณดํ ์ ์๊ฒ ํ๋ ์์ด๋์ด/๋ฐฉ์์ด๊ณ , concurrent rendering์ ๊ทธ๊ฑธ ํฌํจํด์ ๋ฆฌ์กํธ๊ฐ ์ ๋ฐ์ดํธ ์ฐ์ ์์๋ฅผ ์กฐ์ ํ๊ณ , ์ค๊ฐ์ ๋ฉ์ท๋ค๊ฐ ๋ฒ๋ฆฌ๊ณ ๋ค์ ์์ํ ์๋ ์๋ ๋ ํฐ ๋ ๋๋ง ๋ชจ๋ธ์ด๋ค.
์ ๋ฆฌํ๋ฉด,
Time slicing : concurrent rendering์ ๊ฐ๋ฅํ๊ฒ ํ๋ ์ค์ํ ์ฑ์ง ์ค ํ๋
Concurrent rendering : time slicing ๋ณด๋ค๋ ํฐ ๊ฐ๋ (time slicing์ ํฌํจํ ์์ ๋ ๋๋ง ๋ชจ๋ธ)
Time slicing์ concurrent rendering๊ณผ ๋ฌ๋ฆฌ ๋ฆฌ์กํธ ์ ์ฉ ์ฉ์ด๋ ์๋๋ค.
๊ธด ์์ ์ ์กฐ๊ฐ์ผ๋ก ๋๋ ์ ์ค๊ฐ ์ค๊ฐ ๋ค๋ฅธ ์ค์ํ ์์ ์ด ๋ผ์ด๋ค ์ ์๊ฒ ํ๋ ๋ฐฉ์ ์์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ง์ด๋ค.
๋ธ๋ผ์ฐ์ ์์ ๊ธด js ์์ ์ ์ชผ๊ฐ์ ์คํํ๊ฑฐ๋, ์ค์ผ์ค๋ฌ๊ฐ CPU ์์ ์ ์๊ฐ ๋จ์๋ก ๋๋ ์ฒ๋ฆฌํ๊ฑฐ๋, UI ํ๋ ์์ํฌ๊ฐ ๋ ๋๋ง ์์ ์ ์กฐ๊ธ์ฉ ๋๋ ์ ๋ฐ์์ฑ์ ์ ์งํ๋ ๊ฒฝ์ฐ ๋ชจ๋ ํฌํจํ๋ค.
๊ทธ๋ ๋ค๋ฉด setTimeout๋ time slicing ๊ตฌํ ์๋จ ์ค ํ๋์ธ๊ฐ?
๋ง๋ค. ์๋ ์ฝ๋๋ setTimeout์ ์ฌ์ฉํด time slicing์ ๊ตฌํํ ์ฌ๋ก๋ผ๊ณ ๋ณผ ์ ์๋ค.
const items = Array.from({ length: 10000 }, (_, i) => i + 1);
let index = 0;
const chunkSize = 100;
function processChunk() {
const end = Math.min(index + chunkSize, items.length);
for (let i = index; i < end; i++) {
console.log('์ฒ๋ฆฌ์ค:', items[i]);
}
index = end;
if (index < items.length) {
setTimeout(processChunk, 0);
} else {
console.log('๋ชจ๋ ์์
์๋ฃ');
}
}
processChunk();
10000๊ฐ๋ฅผ ํ ๋ฒ์ ๋ค ๋๋ฆฌ์ง ์๊ณ , 100๊ฐ์ฉ ๋์ด์ ์ฒ๋ฆฌํ ๋ค์ ๋ค์ ํ์คํฌ๋ก ๋๊ธฐ๋ ๋ฐฉ์.
๊ทธ๋์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ค๊ฐ์ ํด๋ฆญ, ์คํฌ๋กค, ํ๋ฉด ์
๋ฐ์ดํธ๋ฅผ ํ ๊ธฐํ๋ฅผ ์ป๋๋ค.
setTimeout ๋ง๊ณ ๋, requestAnimationFrame, requestIdleCallback, MessageChannel ๋ฑ์ ์ด์ฉํ ์ ์๋ค.
๋ค์ ํ๋ฉด ๊ทธ๋ฆฌ๊ธฐ ์ง์ ์ ์ด ํจ์ ์คํํ ๊ฒ, ํ๊ณ ์์ฝํด์ฃผ๋ api
const items = Array.from({ length: 5000 }, (_, i) => i + 1); //1๋ถํฐ 5000๊น์ง ์์
๋ชฉ๋ก ์์ฑ
let index = 0; //์ง๊ธ ์ด๋๊น์ง ์ฒ๋ฆฌํ๋์ง ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ
const chunkSize = 100; //ํ ๋ฒ์ ๋ช ๊ฐ์ฉ ์ฒ๋ฆฌํ ์ง
function processChunk() {
const end = Math.min(index + chunkSize, items.length);
for (let i = index; i < end; i++) {
console.log('์ฒ๋ฆฌ์ค:', items[i]);
}
index = end;
if (index < items.length) {
requestAnimationFrame(processChunk); //์์ง ์ฒ๋ฆฌํ ๊ฒ ๋จ์์์ผ๋ฉด ๋ค์ ํ๋ ์ ์ง์ ์ processChunk ์คํ ์์ฝ
}
}
requestAnimationFrame(processChunk); //์ฒซ ์์
๋ธ๋ผ์ฐ์ ๊ฐ ํ๊ฐํด์ง๋ฉด (idle period, ํ๊ฐํ ์๊ฐ) ๋ฎ์ ์ฐ์ ์์ ์์ ์ ์คํํ๋๋ก ์์ฝํ๋ ๋ธ๋ผ์ฐ์ api
const items = Array.from({ length: 5000 }, (_, i) => i + 1); //1๋ถํฐ 5000๊น์ง ์์
๋ชฉ๋ก ์์ฑ
let index = 0; //์ง๊ธ ์ด๋๊น์ง ์ฒ๋ฆฌํ๋์ง ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ
const chunkSize = 100; //ํ ๋ฒ์ ๋ช ๊ฐ์ฉ ์ฒ๋ฆฌํ ์ง
function processChunk() {
const end = Math.min(index + chunkSize, items.length);
for (let i = index; i < end; i++) {
console.log('์ฒ๋ฆฌ์ค:', items[i]);
}
index = end;
if (index < items.length) {
requestIdleCallback(processChunk, { timeout: 1000 }); //์์ง ์ฒ๋ฆฌํ ๊ฒ ๋จ์์์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ํ๊ฐํ ๋ processChunk ์คํ
}
}
requestIdleCallback(processChunk, { timeout: 1000 }); //์ฒซ ์์ (* timeout : 1000 : ๋ธ๋ผ์ฐ์ ๊ฐ ๋ฐ๋น ๋ 1์ด ์์๋ ์คํ ์ต์
)
์๋ฐ์คํฌ๋ฆฝํธ ์์์ ์๋ก ๋ฉ์์ง๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋ ์์ ํต๋ก 2๊ฐ๋ฅผ ๋ง๋ค์ด์ฃผ๋ api
const items = Array.from({ length: 10000 }, (_, i) => i + 1); //๋ฐ์ดํฐ 10000๊ฐ ์ค๋น
let index = 0; //์ง๊ธ ์ด๋๊น์ง ์ฒ๋ฆฌํ๋์ง ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ
const chunkSize = 100; //ํ ๋ฒ์ ๋ช ๊ฐ์ฉ ์ฒ๋ฆฌํ ์ง
const channel = new MessageChannel(); //ํต๋ก 2๊ฐ ์์ฑ
channel.port1.onmessage = processChunk; //port1์ด ๋ฉ์์ง๋ฅผ ๋ฐ์ผ๋ฉด processChunk ์คํ
function processChunk() {
const end = Math.min(index + chunkSize, items.length);
for (let i = index; i < end; i++) {
console.log('์ฒ๋ฆฌ์ค:', items[i]); //index๋ถํฐ end -1 ๊น์ง ๋๋ฉด์ ์์ดํ
์ฒ๋ฆฌ
}
index = end;
if (index < items.length) {
channel.port2.postMessage(null); //์์ง ์ฒ๋ฆฌํ ๊ฒ ๋จ์์์ผ๋ฉด, port2๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด์ ๋ค์ chunk ์คํ์ ์์ฝ
}
}
channel.port2.postMessage(null); //์ฒซ ์์
๊ตฌ๋ถํ์๋ฉด
Time slicing : ์์ ์ ์๊ฒ ๋๋ ์ฒ๋ฆฌํ๋ ์ฑ์ง
Concurrent rendering : ๋ฆฌ์กํธ๊ฐ ์ฐ์ ์์๋ฅผ ๋ณด๊ณ ๋ ๋๋ฅผ ์ ์ฐํ๊ฒ ์ฒ๋ฆฌํ๋ ๋ฐฉ์
startTransition / useTransition : ๊ธํ์ง ์์ ์ ๋ฐ์ดํธ๋ฅผ ๋ค๋ก ๋ฏธ๋ฃจ๊ฒ ํ๋ ๋๊ตฌ
useDeferredValue : ๋ฌด๊ฑฐ์ด ๊ฐ ๋ฐ์์ ์กฐ๊ธ ๋ฆ์ถ๋ ๋๊ตฌ