01. ๐ ๋ธ๋ผ์ฐ์ ๋ ๋๋ง๊ณผ CRP์ ์ฌ์ธต ์๋ฆฌ
๐ ๊ฐ์
๋ธ๋ผ์ฐ์ ๊ฐ HTML์ ํ๋ฉด์ ๊ทธ๋ฆฌ๋ ์ ๊ณผ์ ์ ๋ง์คํฐํ๊ณ , ์ฑ๋ฅ ์ต์ ํ์ ๊ทผ๋ณธ์ธ CRP๋ฅผ ์ ๋ณตํฉ๋๋ค.
๐ ์ด ๋ฉด์ ํญ๋ชฉ์ ๋ชฉํ
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 20๋ถ (ํต์ฌ ์์ฝ: 10๋ถ)
๐บ๏ธ ์ด ์ฑํฐ์ ํ๋ฆ
[๊ฐ๋
์ฌ์ ] โ [์ง๋ฌธ 1: ๋ ๋๋ง ํ์ดํ๋ผ์ธ] โ [์ง๋ฌธ 2: Reflow/Repaint ์ต์ ํ] โ [์ง๋ฌธ 3: ์ ๋๋ฉ์ด์
์ฑ๋ฅ]
๐ฏ ์ด ์ฑํฐ๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- ๋ธ๋ผ์ฐ์ ์ 6๋จ๊ณ ๋ ๋๋ง ํ์ดํ๋ผ์ธ์ ์๋ฒฝํ ์ค๋ช ํ ์ ์์ต๋๋ค.
- ๋ ์ด์์ ์ค๋์ฑ(Layout Thrashing)์ ์์ธ๊ณผ ํด๊ฒฐ์ฑ ์ ์ ์ํ ์ ์์ต๋๋ค.
- GPU ๊ฐ์์ด ์ผ์ด๋๋ ์กฐ๊ฑด๊ณผ ๊ทธ ๊ธฐํ๋น์ฉ์ ๋ ผ๋ฆฌ์ ์ผ๋ก ์ค๋ช ํฉ๋๋ค.
๐ ํต์ฌ ๊ฐ๋ ์ฌ์ (Concept Glossary)
์ง๋ฌธ์ ๋ค์ด๊ฐ๊ธฐ ์ , ์ด ์ฑํฐ๋ฅผ ๊ดํตํ๋ ํต์ฌ ์ฉ์ด๋ค์ ๋จผ์ ์ ๋ฆฌํฉ๋๋ค.
1. CRP (Critical Rendering Path)
๋ธ๋ผ์ฐ์ ๊ฐ HTML, CSS, JavaScript๋ฅผ ์์ ํ์ฌ ์ค์ ํฝ์ ๋ก ๋ณํํ๊ธฐ๊น์ง์ ์ผ๋ จ์ ๋จ๊ณ๋ฅผ ์๋ฏธํฉ๋๋ค. ์ด ๊ฒฝ๋ก๋ฅผ ์ต์ ํํ๋ ๊ฒ์ด ๊ณง ์น ์ฑ๋ฅ ์ต์ ํ์ ์์์ ๋๋ค.
2. ๋ ์ด์์ ์ค๋์ฑ (Layout Thrashing)
JavaScript ์ฝ๋๊ฐ DOM์ ๋ณ๊ฒฝํ๊ณ ์ฆ์ ๊ธฐํํ์ ์ ๋ณด(offsetWidth, scrollTop ๋ฑ)๋ฅผ ์ฝ์ผ๋ ค ํ ๋, ๋ธ๋ผ์ฐ์ ๊ฐ ์ต์ ํ๋ฅผ ํฌ๊ธฐํ๊ณ ๊ฐ์ ๋ก ๋ ์ด์์์ ๋ค์ ๊ณ์ฐํ๊ฒ ๋ง๋๋ ํ์์
๋๋ค. ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ๋ ์ฃผ๋ฒ์
๋๋ค.
3. ์ปดํฌ์งํ (Compositing)
ํ๋ฉด์ ๊ฐ ๋ถ๋ถ์ ๋ณ๋์ ๋ ์ด์ด๋ก ๋๋์ด ๊ทธ๋ฆฐ ๋ค, ๋ง์ง๋ง์ ํ๋๋ก ํฉ์ฑํ๋ ๋จ๊ณ์
๋๋ค. transform, opacity ๋ฑ์ ์ฌ์ฉํ๋ฉด ๋ ์ด์์๊ณผ ํ์ธํธ ๋จ๊ณ๋ฅผ ๊ฑด๋๋ฐ๊ณ GPU์์ ๋ฐ๋ก ํฉ์ฑํ ์ ์์ด ๋งค์ฐ ๋น ๋ฆ
๋๋ค.
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ๐ฃ ์์ฒ ( ์ ์ ): "์ํธ ๋! ์ด๋ฒ์ '์์๋ค ๊ฒ์ํ' ๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํ๋๋ฐ, ์คํฌ๋กคํ ๋๋ง๋ค ํ๋ฉด์ด ๋๋ ๋๊ฒจ์. ๋ถ๋ช ์ฌ์ ์ข์ ๋งฅ๋ถ์ธ๋ฐ ์ ์ด๋ด๊น์? ๐ญ"
- ๐ฆ ์ํธ ( ๋ฆฌ๋ ): "์์ฒ ๋, ํ๋ฉด์ด ๋๊ธด๋ค๋ ๊ฑด ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋น 60ํ๋ ์์ ๊ทธ๋ ค๋ด๋ '๋ ๋๋ง ํ์ดํ๋ผ์ธ' ์ด๋๊ฐ์์ ๋ณ๋ชฉ์ด ์๊ฒผ๋ค๋ ๋ป์ด์์. ๋จ์ํ ์ฝ๋๊ฐ ๋์๊ฐ๋ ๊ฑธ ๋์ด, ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ป๊ฒ ์ผํ๋์ง ์๋ฉด ํด๊ฒฐ์ฑ ์ ๋ฐ๋ก ๋์ต๋๋ค. ์, ๋ฉด์ ์ด๋ผ ์๊ฐํ๊ณ ๋๋ตํด ๋ณด์ธ์."
Q1. ๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง ๊ณผ์ ์ ๋จ๊ณ๋ณ๋ก ์ค๋ช ํด ๋ณด์ธ์.
๐ฏ ์ถ์ ์๋
์ง์์๊ฐ ๋จ์ํ ํ๋ ์์ํฌ ์ฌ์ฉ๋ฒ์ ๋์ด, ์น์ด ๋์ํ๋ ํ๋ถ ํ๊ฒฝ(Browser)์ ๋ฉ์ปค๋์ฆ์ ์ดํดํ๊ณ ์๋์ง ํ์ธํฉ๋๋ค. ์ด๋ ์ฑ๋ฅ ์ต์ ํ ๋ฅ๋ ฅ์ ํ๋จํ๋ ๊ฐ์ฅ ๊ธฐ์ด์ ์ธ ์ฒ๋์ ๋๋ค.
๐ฃ ์์ฒ ์ด์ Naive ๊ตฌํ (Bad Case)
์์ฒ ์ด๋ ๊ฒ์๋ฌผ์ ์ถ๊ฐํ ๋๋ง๋ค ๋ฆฌ์คํธ ์ ์ฒด๋ฅผ ๋ค์ ๊ทธ๋ฆฌ๋ ๋นํจ์จ์ ์ธ ๋ฐฉ์์ ์ฌ์ฉํ์ต๋๋ค.
// ๐ฃ ์์ฒ : "๋ฐ์ดํฐ๊ฐ ๋ฐ๋์์ผ๋ ๊น๋ํ๊ฒ ์๋ก ๊ทธ๋ ค์ผ์ง!"
function updateBoardList(posts) {
const list = document.getElementById('board-list');
list.innerHTML = ''; // โ ๏ธ ๊ธฐ์กด DOM์ ํต์งธ๋ก ๋ ๋ฆฌ๊ณ ์๋ก ์์ฑ (๋น์ผ ๋น์ฉ)
posts.forEach(post => {
list.innerHTML += `<li>${post.title}</li>`; // โ ๏ธ ๋งค ๋ฃจํ๋ง๋ค ๋ฌธ์์ด ํ์ฑ & DOM ํธ๋ฆฌ ์ฌ๊ตฌ์ฑ
});
}๐ฆ ์ํธ์ ํฉํญ ์กฐ์ธ
"์์ฒ ๋,innerHTML +=๋ ๋งค๋ฒ HTML ์ ์ฒด๋ฅผ ๋ฌธ์์ด๋ก ํ์ฑํ๊ณ DOM ํธ๋ฆฌ๋ฅผ ์๋ก ๋ง๋๋ ์ต์ ์ ๋ฐฉ์์ด์์. ๋ธ๋ผ์ฐ์ ๋ ๊ทธ๋๋ง๋ค ํ์ฑ-์คํ์ผ-๋ ์ด์์-ํ์ธํธ๋ฅผ ์ฒ์๋ถํฐ ๋ค์ ํด์ผ ํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ๋ฅผ ๋๋ฌด ๊ดด๋กญํ์ง ๋ง์ธ์."
๐ฆ ์ํธ์ ์ํคํ ์ฒ ๊ฐ์ด๋ (Good Case)
์ํธ ๋ฆฌ๋๋ ๋ธ๋ผ์ฐ์ ๊ฐ ํจ์จ์ ์ผ๋ก ์ผํ ์ ์๋๋ก DocumentFragment์ ์ต์ ํ๋ API๋ฅผ ์ ์ํฉ๋๋ค.
// ๐ฆ ์ํธ: "๋ธ๋ผ์ฐ์ ์๊ฒ '์ต์ข
๊ฒฐ๊ณผ๋ฌผ'๋ง ํ ๋ฒ์ ๋์ ธ์ฃผ์ธ์."
function updateBoardList(posts) {
const list = document.getElementById('board-list');
const fragment = document.createDocumentFragment(); // ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ ์ปจํ
์ด๋
posts.forEach(post => {
const li = document.createElement('li');
li.textContent = post.title; // ํ
์คํธ๋ง ์์ ํ๊ฒ ์ฃผ์
fragment.appendChild(li);
});
list.replaceChildren(fragment); // ๋จ ํ ๋ฒ์ DOM ์กฐ์์ผ๋ก ๋!
}๐ ๋ ๋ฒจ๋ณ ๋ต๋ณ ๊ฐ์ด๋ (Self-Check)
- Level 1 (Junior): "HTML๋ก DOM ํธ๋ฆฌ, CSS๋ก CSSOM ํธ๋ฆฌ๋ฅผ ๋ง๋ญ๋๋ค. ์ด ๋์ ํฉ์ณ Render Tree๋ฅผ ๋ง๋ค๊ณ , ์์์ ํฌ๊ธฐ์ ์์น๋ฅผ ์ ํ๋ Layout, ์์ ์น ํ๋ Paint ๋จ๊ณ๋ฅผ ๊ฑฐ์ณ ํ๋ฉด์ ๋ณด์ฌ์ค๋๋ค."
- Level 2 (Senior): "Render Tree์๋
display: none๊ฐ์ ์์๋ ํฌํจ๋์ง ์์์ ์ธ๊ธํฉ๋๋ค. Layout ์ดํ Paint ๋จ๊ณ์์ ๋ ์ด์ด๊ฐ ๋๋์ด์ง๋ฉฐ, ๋ง์ง๋ง์ Composite ๋จ๊ณ์์ ๋ ์ด์ด๊ฐ ํฉ์ฑ๋๋ค๋ ์ ์ ์ค๋ช ํฉ๋๋ค.transform์์ฑ์ด ์ ๋น ๋ฅธ์ง ํ์ดํ๋ผ์ธ ๊ด์ ์์ ์ฐ๊ฒฐํฉ๋๋ค." - Level 3 (Specialist): "ํ๋์จ์ด ๊ฐ์(GPU)์ด ์ผ์ด๋๋ ํน์ ์กฐ๊ฑด(Will-change ๋ฑ)์ ์ค๋ช ํ๊ณ , ๋ฌด๋ถ๋ณํ ๋ ์ด์ด ์์ฑ์ด ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ(Memory Bloat)์ ์ ๋ฐํ ์ ์๋ค๋ ํธ๋ ์ด๋์คํ๋ฅผ ์ ์ํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์์ง(V8, Blink ๋ฑ)์ ์ต์ ํ ์ ๋ต๊ณผ ์ฐ๊ด ์ง์ด ๋ต๋ณํฉ๋๋ค."
Q2. ๋ฆฌํ๋ก์ฐ(Reflow)์ ๋ฆฌํ์ธํธ(Repaint)์ ์ฐจ์ด์ ์ต์ ํ ์ ๋ต์ ์ค๋ช ํด ๋ณด์ธ์.
๐ฏ ์ถ์ ์๋
๋จ์ํ ์ฉ์ด๋ฅผ ์๋์ง ๋ฌป๋ ๊ฒ์ด ์๋๋ผ, DOM ์กฐ์์ด ๋ธ๋ผ์ฐ์ ๋ด๋ถ ํ๋ก์ธ์ค์ ๋ฏธ์น๋ '๋น์ฉ(Cost)'์ ์ดํดํ๊ณ ์๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ต์ํํ๋ ์ฝ๋ฉ ์ต๊ด์ ๊ฐ์ถ๊ณ ์๋์ง ํ๊ฐํฉ๋๋ค.
๐ฃ ์์ฒ ์ด์ Naive ๊ตฌํ (Bad Case)
์์ฒ ์ด๋ ์คํฌ๋กค ์์น๋ฅผ ํ์ธํ๊ณ ์ถ์ด์ scrollTop์ ์ฝ์ ์งํ, style.height๋ฅผ ๋ณ๊ฒฝํ์ต๋๋ค. ์ด๋ก ์ธํด ๋ธ๋ผ์ฐ์ ๋ ๋์ฐํ ๋นํจ์จ์ ๊ฒช๊ฒ ๋ฉ๋๋ค.
// ๐ฃ ์์ฒ : "์คํฌ๋กค ์์น๋ฅผ ํ์ธํ๊ณ , ๊ทธ์ ๋ง์ถฐ ๋์ด๋ฅผ ์กฐ์ ํด์ผ์ง!"
function adjustLayout() {
const container = document.getElementById('container');
// โ ๏ธ 1. ์ฝ๊ธฐ (Read): ๋ ์ด์์ ์ ๋ณด ์์ฒญ
const currentScroll = container.scrollTop;
// โ ๏ธ 2. ์ฐ๊ธฐ (Write): ๋ ์ด์์ ๋ณ๊ฒฝ
container.style.height = (currentScroll + 100) + 'px';
// โ ๏ธ 3. ๋ค์ ์ฝ๊ธฐ (Read): ๋ฐฉ๊ธ ๋ฐ๋ ๋์ด๋ฅผ ๋ค์ ํ์ธํด์ผ ํจ!
console.log(container.offsetHeight); // โ ์ฌ๊ธฐ์ Reflow ๊ฐ์ ๋ฐ์!
}๐ฆ ์ํธ์ ํฉํญ ์กฐ์ธ
"์์ฒ ๋,scrollTop์ ์ฝ๊ณ ๋ฐ๋กheight๋ฅผ ๋ฐ๊พธ๋ฉด ๋ธ๋ผ์ฐ์ ๋ '์์ฐจ, ๋ฐฉ๊ธ ๋ฐ๋ ๋์ด๋ก ๋ค์ ๊ณ์ฐํด์ผ๊ฒ ๋ค?'๋ผ๋ฉฐ 1๋ฒ๋ถํฐ 4๋ฒ๊น์ง์ ๊ณผ์ ์ ๊ฐ์ ๋ก ๋ฐ๋ณตํฉ๋๋ค. ์ด๊ฑธ **๋ ์ด์์ ์ค๋์ฑ(Layout Thrashing)**์ด๋ผ๊ณ ํด์. ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋ฉ์ถ๋ ์ฃผ๋ฒ์ด์ฃ ."
๐ฆ ์ํธ์ ์ํคํ ์ฒ ๊ฐ์ด๋ (Good Case)
์ํธ ๋ฆฌ๋๋ ์ฝ๊ธฐ์ ์ฐ๊ธฐ ์์ ์ ๋ถ๋ฆฌํ์ฌ ๋ธ๋ผ์ฐ์ ๊ฐ ํ ๋ฒ์ ์ฒ๋ฆฌํ ์ ์๋๋ก ์ ๋ํฉ๋๋ค.
// ๐ฆ ์ํธ: "์ฝ์ ๊ฑด ๋ค ์ฝ๊ณ , ์ธ ๊ฑด ๋ค ์ฐ์ธ์. ์ค๊ฐ์ ๋ผ์ด๋ค์ง ๋ง์ธ์!"
function adjustLayoutOptimized() {
const container = document.getElementById('container');
// 1. ์ฝ๊ธฐ ์์
๋ชจ์ผ๊ธฐ (Read Batch)
// ์ด ๋จ๊ณ์์ ๋ธ๋ผ์ฐ์ ๋ ํ์ํ ์ ๋ณด๋ฅผ ์ต๋ํ ์บ์ฑํฉ๋๋ค.
const currentScroll = container.scrollTop;
const currentHeight = container.offsetHeight;
// 2. ์ฐ๊ธฐ ์์
๋ชจ์ผ๊ธฐ (Write Batch)
// ๊ณ์ฐ๋ ๊ฐ์ผ๋ก ํ ๋ฒ์ ์คํ์ผ์ ์ ์ฉํฉ๋๋ค.
container.style.height = (currentScroll + 100) + 'px';
// 3. ์ด์ ์ฝ์ด๋ ์์ ํฉ๋๋ค. (์ด๋ฏธ ๊ณ์ฐ๋ ๊ฐ์ ๋ฐํ)
console.log(container.offsetHeight); // โ
Reflow ์์!
}๐ ๋ ๋ฒจ๋ณ ๋ต๋ณ ๊ฐ์ด๋ (Self-Check)
- Level 1 (Junior): "Reflow๋ ์์์ ํฌ๊ธฐ๋ ์์น๊ฐ ๋ฐ๋์ด ๋ ์ด์์์ ์ฌ๊ณ์ฐํ๋ ๊ฒ์ด๊ณ , Repaint๋ ์์์ด๋ ๋ฐฐ๊ฒฝ ๋ฑ ์๊ฐ์ ์คํ์ผ๋ง ๋ฐ๋์ด ๋ค์ ๊ทธ๋ฆฌ๋ ๊ฒ์ ๋๋ค. Reflow๊ฐ ๋ ๋น์ฉ์ด ๋ง์ด ๋ญ๋๋ค."
- Level 2 (Senior): "Reflow๋ DOM ํธ๋ฆฌ ์ ์ฒด ๋๋ ์ผ๋ถ์ ๊ธฐํํ์ ๊ตฌ์กฐ๋ฅผ ์ฌ๊ณ์ฐํ๋ ๊ณผ์ ์
๋๋ค.
width,height,margin,padding,font-size๋ณ๊ฒฝ ์ ๋ฐ์ํฉ๋๋ค. Repaint๋ ๋ ์ด์์์ ์ ์ง๋ ์ฑ ์์๋ง ๋ฐ๋๋ ๊ฒฝ์ฐ์ ๋๋ค.color,background-color๋ณ๊ฒฝ ์ ๋ฐ์ํฉ๋๋ค." - Level 3 (Specialist): "๋ ์ด์์ ์ค๋์ฑ(Layout Thrashing)์ ์ธ๊ธํ๋ฉฐ, ์ฝ๊ธฐ(Read)์ ์ฐ๊ธฐ(Write) ์์
์ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ํต์ฌ ์ต์ ํ ์ ๋ต์์ ์ค๋ช
ํฉ๋๋ค. ๋ํ,
transform,opacity๋ฅผ ์ฌ์ฉํ๋ฉด Reflow์ Paint ๋จ๊ณ๋ฅผ ๊ฑด๋๋ฐ๊ณ Composite ๋จ๊ณ์์ ์ฒ๋ฆฌ๋์ด ๊ฐ์ฅ ๋น ๋ฅด๋ค๋ ์ ์ ์ฐ๊ฒฐํฉ๋๋ค."
๐ฃ ์์ฒ ์ด์ ๋ณต๊ธฐ ์ผ๊ธฐ
์ค๋ '์์๋ค ๊ฒ์ํ'์ ์ฑ๋ฅ ์ ํ ์์ธ์ ์ฐพ์๋ค. ๋ฆฌ์คํธ ํ๋ ์ถ๊ฐํ ๋๋ง๋ค ๋ธ๋ผ์ฐ์ ์ฌ์ฅ์ ์ฅ์ด์ง๊ณ ์์๊ตฌ๋... ๐ญ DocumentFragment๋ผ๋ ํ๋ฅญํ ๋๊ตฌ๊ฐ ์๋๋ฐ ์ ์ฐ์ง ๋ชปํ๋!
๐ก "๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง ํ์ดํ๋ผ์ธ์ ์ ํด์ง ์ ํธ ์ฒด๊ณ๊ฐ ์๋ ๊ณ ์๋๋ก์ ๊ฐ๋ค. ๋ด ์ฝ๋๊ฐ ์ญ์ฃผํ์ธ์ง ์ํญ์ธ์ง ๋ ์ฒดํฌํ์."
๋ด์ผ์ ์ด๋ฒคํธ ๋ฃจํ๋ผ๋ ์ ํธ๋ฑ ์ฒด๊ณ๋ฅผ ์ํธ ๋๊ป ์ ๋๋ก ๋ฐฐ์๋ด์ผ๊ฒ ๋ค. ํด๊ทผํ๊ณ ์์ํ ๋งฅ์ฃผ ํ ์ ํ๋ฉด์ ์ค๋ ๋ณต๊ธฐ ๋! ๐บ