Performance Observer API๋ฅผ ํตํด ๋ฐํ์ ์น ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ๊ณ , ํต์ฌ ์น ์งํ๋ฅผ ์ถ์ ํ๋ฉฐ, ์ ์ธ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ์ต์ ํํ๋ ๊ฐ๋ ฅํ๊ณ ๋น์นจํด์ ์ธ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
์น ์ฑ๋ฅ ๊ทน๋ํ: Performance Observer API ์ฌ์ธต ๋ถ์
์ค๋๋ ๋น ๋ฅด๊ฒ ๋ณํํ๋ ๋์งํธ ์ธ๊ณ์์ ์น ์ฑ๋ฅ์ ์ฌ์น๊ฐ ์๋ ํ์ ์ฌํญ์ ๋๋ค. ๋๋ฆฌ๊ฑฐ๋ ์๋ตํ์ง ์๋ ์น์ฌ์ดํธ๋ ์ฌ์ฉ์ ๋ถ๋ง์ ์ผ๊ธฐํ๊ณ ์ดํ๋ฅ ์ ๋์ด๋ฉฐ ๋งค์ถ, ๊ด๊ณ ์์ต ๋๋ ์ฌ์ฉ์ ์ฐธ์ฌ์ ๊ฐ์ ๋น์ฆ๋์ค ๋ชฉํ์ ์ง์ ์ ์ธ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์๋ ๋์ ๊ฐ๋ฐ์๋ ์ผ๋ฐ์ ์ผ๋ก ์ด๊ธฐ ํ์ด์ง ๋ก๋ ์ค์ ํน์ ์์ ์์ ์ฑ๋ฅ์ ์ธก์ ํ๋ ๋๊ตฌ์ ์์กดํด ์์ต๋๋ค. ์ ์ฉํ์ง๋ง ์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ ์ค์ํ ๋ถ๋ถ์ ๋์น๊ณ ์์ต๋๋ค. ์ฆ, ์ฌ์ฉ์๊ฐ ํ์ด์ง์ ์ํธ ์์ฉํ ๋์ ์ ์ฒด์ ์ธ ๊ฒฝํ์ ๋๋ค. ๋ฐํ์ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง์ด ํ์ํ ์ด์ ์ด๋ฉฐ, ๊ฐ์ฅ ๊ฐ๋ ฅํ ๋๊ตฌ๋ Performance Observer API์ ๋๋ค.
๊ธฐ์กด ๋ฐฉ๋ฒ์ ์ข ์ข performance.getEntries()์ ๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ ๋ฐ์ดํฐ๋ฅผ ํด๋งํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์ด๋ ๋นํจ์จ์ ์ด๊ณ ํด๋ง ์ฌ์ด์ ๋ฐ์ํ๋ ์ค์ํ ์ด๋ฒคํธ๋ฅผ ๋์น๊ธฐ ์ฌ์ฐ๋ฉฐ ์ธก์ ํ๋ ค๋ ์ฑ๋ฅ ์ค๋ฒํค๋๋ฅผ ์ถ๊ฐํ ์๋ ์์ต๋๋ค. Performance Observer API๋ ๋ฐ์ํ๋ ์ฑ๋ฅ ์ด๋ฒคํธ๋ฅผ ๊ตฌ๋ ํ๋ ๋น๋๊ธฐ์ ์ ์ค๋ฒํค๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ฌ ์ด ํ๋ก์ธ์ค๋ฅผ ํ์ ํฉ๋๋ค. ์ด ๊ฐ์ด๋์์๋ ํต์ฌ ์น ์งํ๋ฅผ ๋ชจ๋ํฐ๋งํ๊ณ , ๋ณ๋ชฉ ํ์์ ์๋ณํ๊ณ , ๊ถ๊ทน์ ์ผ๋ก ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํด ๋ ๋น ๋ฅด๊ณ ์ฆ๊ฑฐ์ด ์น ๊ฒฝํ์ ๊ตฌ์ถํ ์ ์๋๋ก ์ด ํ์ API์ ๋ํ ์ฌ์ธต์ ์ธ ๋ถ์์ ์ ๊ณตํฉ๋๋ค.
Performance Observer API๋ ๋ฌด์์ ๋๊น?
ํต์ฌ์ ์ผ๋ก Performance Observer API๋ ์ฑ๋ฅ ์ธก์ ์ด๋ฒคํธ(์ฑ๋ฅ ํญ๋ชฉ์ด๋ผ๊ณ ํจ)๋ฅผ ๊ด์ฐฐํ๊ณ ์์งํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ์ธํฐํ์ด์ค์ ๋๋ค. ๋ธ๋ผ์ฐ์ ๋ด์์ ์ฑ๋ฅ ๊ด๋ จ ํ๋์ ์ํ ์ ์ฉ ๋ฆฌ์ค๋๋ผ๊ณ ์๊ฐํ์ญ์์ค. ๋ธ๋ผ์ฐ์ ์ "์์ง ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์์์ต๋๊น?"๋ผ๊ณ ๋ฅ๋์ ์ผ๋ก ๋ฌป๋ ๋์ ๋ธ๋ผ์ฐ์ ๋ "์๋ก์ด ์ฑ๋ฅ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ต๋๋ค! ์์ธํ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค."๋ผ๊ณ ์ฌ์ ์ ์๋ ค์ค๋๋ค.
์ด๋ ๊ด์ฐฐ์ ํจํด์ ํตํด ๋ฌ์ฑ๋ฉ๋๋ค. ๊ด์ฐฐ์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค๊ณ ๊ด์ฌ ์๋ ์ฑ๋ฅ ์ด๋ฒคํธ ์ ํ(์: ํฐ ํ์ธํธ, ์ฌ์ฉ์ ์ ๋ ฅ, ๋ ์ด์์ ๋ณ๊ฒฝ)์ ์๋ ค์ฃผ๊ณ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ง์ ๋ ์ ํ์ ์ ์ด๋ฒคํธ๊ฐ ๋ธ๋ผ์ฐ์ ์ ์ฑ๋ฅ ํ์๋ผ์ธ์ ๊ธฐ๋ก๋ ๋๋ง๋ค ์ ํญ๋ชฉ ๋ชฉ๋ก๊ณผ ํจ๊ป ์ฝ๋ฐฑ ํจ์๊ฐ ํธ์ถ๋ฉ๋๋ค. ์ด ๋น๋๊ธฐ์ ํธ์ ๊ธฐ๋ฐ ๋ชจ๋ธ์ performance.getEntries()๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ํธ์ถํ๋ ๊ธฐ์กด์ ํ ๊ธฐ๋ฐ ๋ชจ๋ธ๋ณด๋ค ํจ์ฌ ํจ์จ์ ์ด๊ณ ์์ ์ ์ ๋๋ค.
๊ธฐ์กด ๋ฐฉ์ ๋ ์๋ก์ด ๋ฐฉ์
Performance Observer์ ํ์ ์ ์ดํดํ๊ธฐ ์ํด ๋ ๊ฐ์ง ์ ๊ทผ ๋ฐฉ์์ ๋น๊ตํด ๋ณด๊ฒ ์ต๋๋ค.
- ๊ธฐ์กด ๋ฐฉ์(ํด๋ง): setTimeout ๋๋ requestAnimationFrame์ ์ฌ์ฉํ์ฌ performance.getEntriesByName('my-metric')์ ์ฃผ๊ธฐ์ ์ผ๋ก ํธ์ถํ์ฌ ๋ฉํธ๋ฆญ์ด ๊ธฐ๋ก๋์๋์ง ํ์ธํ ์ ์์ต๋๋ค. ๋๋ฌด ๋ฆ๊ฒ ํ์ธํ์ฌ ์ด๋ฒคํธ๋ฅผ ๋์น๊ฑฐ๋ ๋๋ฌด ์์ฃผ ํ์ธํ์ฌ CPU ์ฃผ๊ธฐ๋ฅผ ๋ญ๋นํ ์ ์์ผ๋ฏ๋ก ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ํญ๋ชฉ์ ์ ๊ธฐ์ ์ผ๋ก ์ง์ฐ์ง ์์ผ๋ฉด ๋ธ๋ผ์ฐ์ ์ ์ฑ๋ฅ ๋ฒํผ๋ฅผ ์ฑ์ธ ์ํ๋ ์์ต๋๋ค.
- ์๋ก์ด ๋ฐฉ์(๊ด์ฐฐ): PerformanceObserver๋ฅผ ํ ๋ฒ ์ค์ ํฉ๋๋ค. ์ต์ํ์ ๋ฆฌ์์ค๋ฅผ ์๋นํ๋ฉด์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์กฐ์ฉํ ๋๊ธฐํฉ๋๋ค. ํ์ด์ง ๋ก๋ ํ 1๋ฐ๋ฆฌ์ด๋ ์ฌ์ฉ์ ์ธ์ ์ ๋ค์ด๊ฐ ์ง 10๋ถ์ด๋ ๊ด๋ จ ์ฑ๋ฅ ํญ๋ชฉ์ด ๊ธฐ๋ก๋๋ ์ฆ์ ์ฝ๋๋ก ์๋ฆผ์ด ์ ์ก๋ฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ด๋ฒคํธ๋ฅผ ๋์น์ง ์๊ณ ๋ชจ๋ํฐ๋ง ์ฝ๋๊ฐ ์ต๋ํ ํจ์จ์ ์ผ๋ก ์๋ํฉ๋๋ค.
Performance Observer๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์
Performance Observer API๋ฅผ ๊ฐ๋ฐ ์ํฌํ๋ก์ ํตํฉํ๋ฉด ์ ์ธ๊ณ์ ์ผ๋ก ๋๋ฌํ๋ ค๋ ์ต์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ํ ์ฌ๋ฌ ๊ฐ์ง ์ด์ ์ ์ป์ ์ ์์ต๋๋ค.
- ๋น์นจํด์ ๋ชจ๋ํฐ๋ง: ๊ด์ฐฐ์์ ์ฝ๋ฐฑ์ ์ผ๋ฐ์ ์ผ๋ก ์ ํด ๊ธฐ๊ฐ ๋์ ์คํ๋๋ฏ๋ก ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง ์ฝ๋๊ฐ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ฐฉํดํ๊ฑฐ๋ ๊ธฐ๋ณธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์์ต๋๋ค. ๊ฐ๋ณ๊ณ ์ฑ๋ฅ์ ๋ฏธ๋ฏธํ ์ํฅ์ ๋ฏธ์น๋๋ก ์ค๊ณ๋์์ต๋๋ค.
- ์ข ํฉ์ ์ธ ๋ฐํ์ ๋ฐ์ดํฐ: ์น์ ์ญ๋์ ์ ๋๋ค. ์ฑ๋ฅ ๋ฌธ์ ๋ ๋ก๋ ์๊ฐ์๋ง ๋ฐ์ํ๋ ๊ฒ์ด ์๋๋๋ค. ์ฌ์ฉ์๋ ๋ณต์กํ ์ ๋๋ฉ์ด์ ์ ํธ๋ฆฌ๊ฑฐํ๊ฑฐ๋ ์คํฌ๋กคํ์ฌ ๋ ๋ง์ ์ฝํ ์ธ ๋ฅผ ๋ก๋ํ๊ฑฐ๋ ์ด๊ธฐ ํ์ด์ง๊ฐ ์ ์ฐฉ๋ ํ์๋ ๋ฌด๊ฑฐ์ด ๊ตฌ์ฑ ์์์ ์ํธ ์์ฉํ ์ ์์ต๋๋ค. Performance Observer๋ ์ด๋ฌํ ๋ฐํ์ ์ด๋ฒคํธ๋ฅผ ์บก์ฒํ์ฌ ์ ์ฒด ์ฌ์ฉ์ ์ธ์ ์ ๋ํ ์๋ฒฝํ ๊ทธ๋ฆผ์ ์ ๊ณตํฉ๋๋ค.
- ๋ฏธ๋ ๋ณด์ฅ ๋ฐ ํ์คํ: ์ฑ๋ฅ ๋ฐ์ดํฐ ์์ง์ ์ํ W3C ๊ถ์ฅ ํ์ค์ ๋๋ค. ์๋ก์ด ์ฑ๋ฅ ๋ฉํธ๋ฆญ๊ณผ API๋ ์ด๋ฅผ ํตํฉํ๋๋ก ์ค๊ณ๋์ด ํ๋ก์ ํธ์ ์ง์ ๊ฐ๋ฅํ๊ณ ๋ฏธ๋ ์งํฅ์ ์ธ ์ ํ์ด ๋ฉ๋๋ค.
- ์ค์ฌ์ฉ์ ๋ชจ๋ํฐ๋ง(RUM)์ ๊ธฐ๋ฐ: ๋ค์ํ ๊ตญ๊ฐ, ์ฅ์น ๋ฐ ๋คํธ์ํฌ ์กฐ๊ฑด์์ ์ฌ์ฉ์๋ฅผ ์ํ ์ฌ์ดํธ ์ฑ๋ฅ์ ์ง์ ์ผ๋ก ์ดํดํ๋ ค๋ฉด ์ค์ ์ธ์ ์ ๋ฐ์ดํฐ๊ฐ ํ์ํฉ๋๋ค. Performance Observer๋ ๊ฐ๋ ฅํ RUM ์๋ฃจ์ ์ ๊ตฌ์ถํ๊ธฐ ์ํ ์ด์์ ์ธ ๋๊ตฌ์ด๋ฉฐ ์ค์ํ ๋ฉํธ๋ฆญ์ ์์งํ์ฌ ์ง๊ณ ๋ฐ ๋ถ์์ ์ํด ๋ถ์ ์๋น์ค๋ก ๋ณด๋ผ ์ ์์ต๋๋ค.
- ๊ฒฝ์ ์กฐ๊ฑด ์ ๊ฑฐ: ํด๋ง์ ์ฌ์ฉํ๋ฉด ๊ธฐ๋ก๋๊ธฐ ์ ์ ์ฑ๋ฅ ํญ๋ชฉ์ ์ก์ธ์คํ๋ ค๊ณ ํ ์ ์์ต๋๋ค. ๊ด์ฐฐ์ ๋ชจ๋ธ์ ํญ๋ชฉ์ ์ฌ์ฉํ ์ ์๊ฒ ๋ ํ์๋ง ์ฝ๋๊ฐ ์คํ๋๋ฏ๋ก ์ด๋ฌํ ๊ฒฝ์ ์กฐ๊ฑด์ ์์ ํ ์ ๊ฑฐํฉ๋๋ค.
์์ํ๊ธฐ: Performance Observer์ ๊ธฐ๋ณธ ์ฌํญ
API ์ฌ์ฉ์ ๊ฐ๋จํฉ๋๋ค. ํ๋ก์ธ์ค์๋ ๊ด์ฐฐ์ ๋ง๋ค๊ธฐ, ์ฝ๋ฐฑ ์ ์ ๋ฐ ๊ด์ฐฐ์์๊ฒ ๊ฐ์ํ ํญ๋ชฉ ์๋ฆฌ๊ธฐ๋ผ๋ ์ธ ๊ฐ์ง ์ฃผ์ ๋จ๊ณ๊ฐ ํฌํจ๋ฉ๋๋ค.
1. ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ ๊ด์ฐฐ์ ๋ง๋ค๊ธฐ
๋จผ์ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ ๋ฌํ์ฌ PerformanceObserver ๊ฐ์ฒด๋ฅผ ์ธ์คํด์คํํฉ๋๋ค. ์ด ํจ์๋ ์ ํญ๋ชฉ์ด ๊ฐ์ง๋ ๋๋ง๋ค ์คํ๋ฉ๋๋ค.
const observer = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { console.log('Entry Type:', entry.entryType); console.log('Entry Name:', entry.name); console.log('Start Time:', entry.startTime); console.log('Duration:', entry.duration); } });
์ฝ๋ฐฑ์ PerformanceObserverEntryList ๊ฐ์ฒด๋ฅผ ๋ฐ์ต๋๋ค. ์ด ๋ชฉ๋ก์์ getEntries() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์๋ก ๊ด์ฐฐ๋ ๋ชจ๋ ์ฑ๋ฅ ํญ๋ชฉ์ ๋ฐฐ์ด์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
2. ํน์ ํญ๋ชฉ ์ ํ ๊ด์ฐฐ
๊ด์ฐฐ์๋ ๊ฐ์ํ ํญ๋ชฉ์ ์๋ ค์ค ๋๊น์ง ์๋ฌด๊ฒ๋ ํ์ง ์์ต๋๋ค. .observe() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ์ํํฉ๋๋ค. ์ด ๋ฉ์๋๋ ๊ด์ฌ ์๋ ์ฑ๋ฅ ํญ๋ชฉ ์ ํ์ ๋ํ๋ด๋ ๋ฌธ์์ด ๋ฐฐ์ด์ธ entryTypes ์์ฑ(๋๋ ์ผ๋ถ ์ต์ ๊ฒฝ์ฐ์๋ ๋จ์ผ ์ ํ์ ๊ฒฝ์ฐ type)์ด ์๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํฉ๋๋ค.
// ๋ ๊ฐ์ง ์ ํ์ ํญ๋ชฉ ๊ด์ฐฐ ์์ observer.observe({ entryTypes: ['mark', 'measure'] });
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ํญ๋ชฉ ์ ํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- 'resource': ์คํฌ๋ฆฝํธ, ์ด๋ฏธ์ง ๋ฐ ์คํ์ผ์ํธ์ ๊ฐ์ ์์ฐ์ ๋ํ ๋คํธ์ํฌ ์์ฒญ์ ๋ํ ์ธ๋ถ ์ ๋ณด.
- 'paint': ์ฒซ ๋ฒ์งธ ํ์ธํธ ๋ฐ ์ฒซ ๋ฒ์งธ ์ฝํ ์ธ ํ์ธํธ์ ํ์ด๋ฐ.
- 'largest-contentful-paint': ์ธ์ง๋ ๋ก๋ ์๋์ ๋ํ ํต์ฌ ์น ์งํ.
- 'layout-shift': ์๊ฐ์ ์์ ์ฑ์ ๋ํ ํต์ฌ ์น ์งํ.
- 'first-input': First Input Delay ํต์ฌ ์น ์งํ์ ์ฌ์ฉ๋๋ ์ฒซ ๋ฒ์งธ ์ฌ์ฉ์ ์ํธ ์์ฉ์ ๋ํ ์ ๋ณด.
- 'longtask': ์๋ต์ฑ์ ๋จ์ด๋จ๋ฆด ์ ์๋ 50๋ฐ๋ฆฌ์ด๋ณด๋ค ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ธฐ๋ณธ ์ค๋ ๋์ ์์ ์ ์๋ณํฉ๋๋ค.
- 'mark' & 'measure': ์ฌ์ฉ์ ํ์ด๋ฐ API๋ฅผ ์ฌ์ฉํ์ฌ ์์ ์ ์ฝ๋์์ ์ ์ํ๋ ์ฌ์ฉ์ ์ง์ ๋ง์ปค ๋ฐ ์ธก์ ๊ฐ.
3. ๊ด์ฐฐ์ ์ค์ง
๋ ์ด์ ๋ฐ์ดํฐ๋ฅผ ์์งํ ํ์๊ฐ ์์ ๋ ๋ฆฌ์์ค๋ฅผ ํ๋ณดํ๊ธฐ ์ํด ๊ด์ฐฐ์์ ์ฐ๊ฒฐ์ ๋๋ ๊ฒ์ด ์ข์ต๋๋ค.
observer.disconnect();
์ค์ ์ฌ์ฉ ์ฌ๋ก: ํต์ฌ ์น ์งํ ๋ชจ๋ํฐ๋ง
ํต์ฌ ์น ์งํ๋ Google์ด ์นํ์ด์ง์ ์ ๋ฐ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์์ ์ค์ํ๋ค๊ณ ๊ฐ์ฃผํ๋ ํน์ ์์ ์งํฉ์ ๋๋ค. ์ด๋ฅผ ๋ชจ๋ํฐ๋งํ๋ ๊ฒ์ Performance Observer API์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ์์ฉ ํ๋ก๊ทธ๋จ ์ค ํ๋์ ๋๋ค. ๊ฐ ํญ๋ชฉ์ ์ธก์ ํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Largest Contentful Paint(LCP) ๋ชจ๋ํฐ๋ง
LCP๋ ๋ก๋ฉ ์ฑ๋ฅ์ ์ธก์ ํฉ๋๋ค. ์ฃผ์ ์ฝํ ์ธ ๊ฐ ๋ก๋๋์์ ๊ฐ๋ฅ์ฑ์ด ์๋ ํ์ด์ง ๋ก๋ ํ์๋ผ์ธ์ ์ง์ ์ ํ์ํฉ๋๋ค. ์ข์ LCP ์ ์๋ 2.5์ด ์ดํ์ ๋๋ค.
LCP ์์๋ ํ์ด์ง๊ฐ ๋ก๋๋ ๋ ๋ณ๊ฒฝ๋ ์ ์์ต๋๋ค. ์ฒ์์๋ ์ ๋ชฉ์ด LCP ์์์ผ ์ ์์ง๋ง ๋์ค์ ๋ ํฐ ์ด๋ฏธ์ง๊ฐ ๋ก๋๋์ด ์ LCP ์์๊ฐ ๋ ์ ์์ต๋๋ค. ์ด๊ฒ์ด Performance Observer๊ฐ ์๋ฒฝํ ์ด์ ์ ๋๋ค. ๋ ๋๋ง๋ ๋๋ง๋ค ์ ์ฌ์ ์ธ ๊ฐ LCP ํ๋ณด์ ๋ํด ์๋ ค์ค๋๋ค.
// LCP๋ฅผ ๊ด์ฐฐํ๊ณ ์ต์ข ๊ฐ ๊ธฐ๋ก let lcpValue = 0; const lcpObserver = new PerformanceObserver((entryList) => { const entries = entryList.getEntries(); // ๋ง์ง๋ง ํญ๋ชฉ์ ์ต์ LCP ํ๋ณด์ ๋๋ค. const lastEntry = entries[entries.length - 1]; lcpValue = lastEntry.startTime; console.log(`LCP updated: ${lcpValue.toFixed(2)}ms`, lastEntry.element); }); lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true }); // ์ฌ์ฉ์ ์ํธ ์์ฉ ํ์๋ ๊ด์ฐฐ์์ ์ฐ๊ฒฐ์ ๋๋ ๊ฒ์ด ์ข์ต๋๋ค. // ์ํธ ์์ฉ์ผ๋ก ์ธํด ์๋ก์ด LCP ํ๋ณด๊ฐ ๋์คํจ์น๋์ง ์์ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. // window.addEventListener('beforeunload', () => lcpObserver.disconnect());
buffered: true์ ์ฌ์ฉ์ ์ฃผ๋ชฉํ์ญ์์ค. ์ด๋ observe() ๋ฉ์๋๊ฐ ํธ์ถ๋๊ธฐ *์ ์* ๊ธฐ๋ก๋ ํญ๋ชฉ์ ํฌํจํ๋๋ก ๊ด์ฐฐ์์๊ฒ ์ง์ํ๋ ์ค์ํ ์ต์ ์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ด๊ธฐ LCP ์ด๋ฒคํธ๋ฅผ ๋์น์ง ์์ต๋๋ค.
First Input Delay(FID) ๋ฐ Interaction to Next Paint(INP) ๋ชจ๋ํฐ๋ง
์ด๋ฌํ ๋ฉํธ๋ฆญ์ ์ํธ ์์ฉ์ฑ์ ์ธก์ ํฉ๋๋ค. ํ์ด์ง์ ์ฒ์ ์ํธ ์์ฉํ๋ ค๊ณ ํ ๋ ์ฌ์ฉ์์ ๊ฒฝํ์ ์ ๋ํํฉ๋๋ค.
First Input Delay(FID)๋ ์ฌ์ฉ์๊ฐ ํ์ด์ง์ ์ฒ์ ์ํธ ์์ฉํ๋ ์๊ฐ(์: ๋ฒํผ ํด๋ฆญ)๋ถํฐ ๋ธ๋ผ์ฐ์ ๊ฐ ํด๋น ์ํธ ์์ฉ์ ๋ํ ์๋ต์ผ๋ก ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ค์ ๋ก ์์ํ ์ ์๋ ์๊ฐ๊น์ง ์ธก์ ํฉ๋๋ค. ์ข์ FID๋ 100๋ฐ๋ฆฌ์ด ์ดํ์ ๋๋ค.
Interaction to Next Paint(INP)๋ 2024๋ 3์์ ํต์ฌ ์น ์งํ๋ก FID๋ฅผ ๋์ฒดํ ์๋กญ๊ณ ํฌ๊ด์ ์ธ ๋ฉํธ๋ฆญ์ ๋๋ค. FID๋ *์ฒซ ๋ฒ์งธ* ์ํธ ์์ฉ์ *์ง์ฐ*๋ง ์ธก์ ํ๋ ๋ฐ๋ฉด INP๋ ํ์ด์ง ์๋ช ์ฃผ๊ธฐ ์ ๋ฐ์ ๊ฑธ์ณ *๋ชจ๋ * ์ฌ์ฉ์ ์ํธ ์์ฉ์ *์ด ๋๊ธฐ ์๊ฐ*์ ํ๊ฐํ์ฌ ์ต์ ์ ํญ๋ชฉ์ ๋ณด๊ณ ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ ๋ฐ์ ์ธ ์๋ต์ฑ์ ๋ํ ๋ ๋์ ๊ทธ๋ฆผ์ ์ป์ ์ ์์ต๋๋ค. ์ข์ INP๋ 200๋ฐ๋ฆฌ์ด ์ดํ์ ๋๋ค.
'first-input' ํญ๋ชฉ ์ ํ์ ์ฌ์ฉํ์ฌ FID๋ฅผ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
// FID ๊ด์ฐฐ const fidObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { const fid = entry.processingStart - entry.startTime; console.log(`FID: ${fid.toFixed(2)}ms`); // ์ฒซ ๋ฒ์งธ ์ ๋ ฅ์ด ๋ณด๊ณ ๋ ํ ์ฐ๊ฒฐ ๋๊ธฐ fidObserver.disconnect(); } }); fidObserver.observe({ type: 'first-input', buffered: true });
INP ๋ชจ๋ํฐ๋ง์ ์ด๋ฒคํธ์ ์ ์ฒด ์ง์ ์๊ฐ์ ์ดํด๋ณด๋ฏ๋ก ์ฝ๊ฐ ๋ ๋ณต์กํฉ๋๋ค. 'event' ํญ๋ชฉ ์ ํ์ ๊ด์ฐฐํ๊ณ ์ง์ ์๊ฐ์ ๊ณ์ฐํ์ฌ ๊ฐ์ฅ ๊ธด ํญ๋ชฉ์ ์ถ์ ํฉ๋๋ค.
// ๋จ์ํ๋ INP ๋ชจ๋ํฐ๋ง ์์ let worstInp = 0; const inpObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // INP๋ ์ด๋ฒคํธ์ ์ง์ ์๊ฐ์ ๋๋ค. const inp = entry.duration; // ํ์ฌ ์ต์ ์ ๊ฒ๋ณด๋ค ๋ ๊ธด ์ํธ ์์ฉ๋ง ์ ๊ฒฝ ์๋๋ค. if (inp > worstInp) { worstInp = inp; console.log(`New worst INP: ${worstInp.toFixed(2)}ms`); } } }); inpObserver.observe({ type: 'event', durationThreshold: 16, buffered: true }); // durationThreshold๋ ๋งค์ฐ ์งง๊ณ ์ค์ํ์ง ์์ ์ด๋ฒคํธ์ผ ๊ฐ๋ฅ์ฑ์ด ๋์ ์ด๋ฒคํธ๋ฅผ ํํฐ๋งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
Cumulative Layout Shift(CLS) ๋ชจ๋ํฐ๋ง
CLS๋ ์๊ฐ์ ์์ ์ฑ์ ์ธก์ ํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์๊ธฐ์น ์์ ๋ ์ด์์ ๋ณ๊ฒฝ์ ์ผ๋ง๋ ์์ฃผ ๊ฒฝํํ๋์ง ์ ๋ํํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. ์ฝํ ์ธ ๊ฐ ๊ฒฝ๊ณ ์์ด ํ์ด์ง์์ ์ด๋ํ๋ ์ง์ฆ๋๋ ๊ฒฝํ์ ๋๋ค. ์ข์ CLS ์ ์๋ 0.1 ์ดํ์ ๋๋ค.
์ ์๋ ๋ชจ๋ ๊ฐ๋ณ ๋ ์ด์์ ๋ณ๊ฒฝ ์ ์์ ์ง๊ณ์ ๋๋ค. Performance Observer๋ ๊ฐ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ฐ์ํ ๋ ๋ณด๊ณ ํ๋ฏ๋ก ์ฌ๊ธฐ์์ ํ์์ ์ ๋๋ค.
// ์ด CLS ์ ์ ๊ด์ฐฐ ๋ฐ ๊ณ์ฐ let clsScore = 0; const clsObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // ์ฌ์ฉ์ ์ ๋ ฅ์ผ๋ก ์ธํด ๋ฐ์ํ ๋ณ๊ฒฝ ์ฌํญ์ ๊ณ์ฐํ์ง ์์ผ๋ ค๊ณ ํฉ๋๋ค. if (!entry.hadRecentInput) { clsScore += entry.value; console.log(`Current CLS score: ${clsScore.toFixed(4)}`); } } }); clsObserver.observe({ type: 'layout-shift', buffered: true });
hadRecentInput ์์ฑ์ ์ค์ํฉ๋๋ค. ๋ฉ๋ด๋ฅผ ํ์ฅํ๋ ๋ฒํผ ํด๋ฆญ๊ณผ ๊ฐ์ด ์ฌ์ฉ์ ์์ ์ ๋ํ ์๋ต์ผ๋ก ๋ฐ์ํ๋ ํฉ๋ฒ์ ์ธ ๋ ์ด์์ ๋ณ๊ฒฝ ์ฌํญ์ ํํฐ๋งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. ์ด๋ CLS ์ ์์ ํฌํจ๋์ด์๋ ์ ๋ฉ๋๋ค.
ํต์ฌ ์น ์งํ๋ฅผ ๋์ด: ๋ค๋ฅธ ๊ฐ๋ ฅํ ํญ๋ชฉ ์ ํ
ํต์ฌ ์น ์งํ๋ ํ๋ฅญํ ์ถ๋ฐ์ ์ด์ง๋ง Performance Observer๋ ํจ์ฌ ๋ ๋ง์ ๊ฒ์ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค. ๋ช ๊ฐ์ง ๋ค๋ฅธ ๋งค์ฐ ์ ์ฉํ ํญ๋ชฉ ์ ํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Long Tasks(`longtask`) ์ถ์
Long Tasks API๋ ๊ธฐ๋ณธ ์ค๋ ๋๋ฅผ 50๋ฐ๋ฆฌ์ด ์ด์ ์ฐจ์งํ๋ ์์ ์ ๋ ธ์ถํฉ๋๋ค. ๊ธฐ๋ณธ ์ค๋ ๋๊ฐ ์ฌ์ฉ ์ค์ธ ๋์ ํ์ด์ง๊ฐ ์ฌ์ฉ์ ์ ๋ ฅ์ ์๋ตํ ์ ์์ด ๋๋ฆฌ๊ฑฐ๋ ๊ณ ์ ๋ ํ๊ฒฝ์ด ๋ฐ์ํ๋ฏ๋ก ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ์ด๋ฌํ ์์ ์ ์๋ณํ๋ ๊ฒ์ INP๋ฅผ ๊ฐ์ ํ๋ ๋ฐ ์ค์ํฉ๋๋ค.
// ๊ธด ์์ ๊ด์ฐฐ const longTaskObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { console.log(`Long Task Detected: ${entry.duration.toFixed(2)}ms`); // 'attribution' ์์ฑ์ ๋๋๋ก ๊ธด ์์ ์ ์ ๋ฐํ ์์ธ์ ์๋ ค์ค ์ ์์ต๋๋ค. console.log('Attribution:', entry.attribution); } }); longTaskObserver.observe({ type: 'longtask', buffered: true });
๋ฆฌ์์ค ํ์ด๋ฐ ๋ถ์(`resource`)
์์ฐ์ด ๋ก๋๋๋ ๋ฐฉ์์ ์ดํดํ๋ ๊ฒ์ ์ฑ๋ฅ ํ๋์ ๊ธฐ๋ณธ์ ๋๋ค. 'resource' ํญ๋ชฉ ์ ํ์ DNS ์กฐํ, TCP ์ฐ๊ฒฐ ๋ฐ ์ฝํ ์ธ ๋ค์ด๋ก๋ ์๊ฐ์ ํฌํจํ์ฌ ํ์ด์ง์ ๋ชจ๋ ๋ฆฌ์์ค์ ๋ํ ์์ธํ ๋คํธ์ํฌ ํ์ด๋ฐ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
// ๋ฆฌ์์ค ํ์ด๋ฐ ๊ด์ฐฐ const resourceObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // ๋ก๋ ์๋๊ฐ ๋๋ฆฐ ์ด๋ฏธ์ง๋ฅผ ์ฐพ์๋ณด๊ฒ ์ต๋๋ค. if (entry.initiatorType === 'img' && entry.duration > 500) { console.warn(`Slow image detected: ${entry.name}`, `Duration: ${entry.duration.toFixed(2)}ms`); } } }); // ์ด ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋๊ธฐ ์ ์ ๋ก๋๋ ์์ฐ์ ์บก์ฒํ๋ ค๋ฉด // 'buffered: true'๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฑฐ์ ํญ์ ํ์ํฉ๋๋ค. resourceObserver.observe({ type: 'resource', buffered: true });
์ฌ์ฉ์ ์ง์ ์ฑ๋ฅ ๋งํฌ ์ธก์ (`mark` ๋ฐ `measure`)
๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ ํ๋ฆฌ์ผ์ด์ ๋ณ ๋ ผ๋ฆฌ์ ์ฑ๋ฅ์ ์ธก์ ํด์ผ ํ ์ ์์ต๋๋ค. ์ฌ์ฉ์ ํ์ด๋ฐ API๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์ ์ง์ ํ์์คํฌํ๋ฅผ ๋ง๋ค๊ณ ํ์์คํฌํ ๊ฐ์ ๊ธฐ๊ฐ์ ์ธก์ ํ ์ ์์ต๋๋ค.
- performance.mark('start-operation'): 'start-operation'์ด๋ผ๋ ํ์์คํฌํ๋ฅผ ๋ง๋ญ๋๋ค.
- performance.mark('end-operation'): ๋ค๋ฅธ ํ์์คํฌํ๋ฅผ ๋ง๋ญ๋๋ค.
- performance.measure('my-operation', 'start-operation', 'end-operation'): ๋ ๋งํฌ ๊ฐ์ ์ธก์ ๊ฐ์ ๋ง๋ญ๋๋ค.
Performance Observer๋ JavaScript ํ๋ ์์ํฌ์ ๊ตฌ์ฑ ์์ ๋ ๋๋ง ์๊ฐ ๋๋ ์ค์ํ API ํธ์ถ ๋ฐ ํ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ธฐ๊ฐ๊ณผ ๊ฐ์ ํญ๋ชฉ์ ๋ํ ํ์ด๋ฐ ๋ฐ์ดํฐ๋ฅผ ์์งํ๋ ๋ฐ ์ ํฉํ ์ด๋ฌํ ์ฌ์ฉ์ ์ง์ 'mark' ๋ฐ 'measure' ํญ๋ชฉ์ ์์ ํ ์ ์์ต๋๋ค.
// ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์์: performance.mark('start-data-processing'); // ... ๋ช ๊ฐ์ง ๋ณต์กํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ... performance.mark('end-data-processing'); performance.measure('data-processing-duration', 'start-data-processing', 'end-data-processing'); // ๋ชจ๋ํฐ๋ง ์คํฌ๋ฆฝํธ์์: const customObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntriesByName('data-processing-duration')) { console.log(`Custom Measurement '${entry.name}': ${entry.duration.toFixed(2)}ms`); } }); customObserver.observe({ entryTypes: ['measure'] });
๊ณ ๊ธ ๊ฐ๋ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
์ ๋ฌธ์ ์ธ ํ๋ก๋์ ํ๊ฒฝ์์ Performance Observer API๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
- ํญ์ `buffered: true`๋ฅผ ๊ณ ๋ คํ์ญ์์ค.: ํ์ด์ง ๋ก๋ ์ด๊ธฐ์ ๋ฐ์ํ ์ ์๋ ํญ๋ชฉ ์ ํ(์: 'resource', 'paint' ๋๋ 'largest-contentful-paint')์ ๊ฒฝ์ฐ ๋ฒํผ๋ง๋ ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋๋ฝ์ ๋ฐฉ์งํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
- ๋ธ๋ผ์ฐ์ ์ง์ ํ์ธ: ์ต์ ๋ธ๋ผ์ฐ์ ์์ ๋๋ฆฌ ์ง์๋์ง๋ง ์ฌ์ฉํ๊ธฐ ์ ์ ํญ์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํน์ ๋ธ๋ผ์ฐ์ ์์ ์ง์๋๋ ํญ๋ชฉ ์ ํ์ ํ์ธํ ์๋ ์์ต๋๋ค.
- if ('PerformanceObserver' in window && PerformanceObserver.supportedEntryTypes.includes('longtask')) { // ๊ธด ์์ ์ PerformanceObserver๋ฅผ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. }
- ๋ถ์ ์๋น์ค๋ก ๋ฐ์ดํฐ ๋ณด๋ด๊ธฐ: ์ฝ์์ ๋ฐ์ดํฐ๋ฅผ ๋ก๊น ํ๋ ๊ฒ์ ๊ฐ๋ฐ์ ์ ํฉํ์ง๋ง ์ค์ ๋ชจ๋ํฐ๋ง์ ๊ฒฝ์ฐ ์ด ๋ฐ์ดํฐ๋ฅผ ์ง๊ณํด์ผ ํฉ๋๋ค. ํด๋ผ์ด์ธํธ์์ ์ด ์๊ฒฉ ๋ถ์์ ๋ณด๋ด๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ navigator.sendBeacon() API๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์๋ฒ์ ์๋์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋๋ก ์ค๊ณ๋ ๋น์ฐจ๋จ ๋ฉ์ปค๋์ฆ์ด๋ฉฐ ํ์ด์ง๊ฐ ์ธ๋ก๋๋๋ ๊ฒฝ์ฐ์๋ ์์ ์ ์ผ๋ก ์๋ํฉ๋๋ค.
- ๊ด์ฌ์ฌ๋ณ๋ก ๊ด์ฐฐ์ ๊ทธ๋ฃนํ: ์ฌ๋ฌ ํญ๋ชฉ ์ ํ์ ๋ํด ๋จ์ผ ๊ด์ฐฐ์๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง ๋ค๋ฅธ ๊ด์ฌ์ฌ์ ๋ํด ๋ณ๋์ ๊ด์ฐฐ์๋ฅผ ๋ง๋๋ ๊ฒ์ด ๋ ๊น๋ํฉ๋๋ค(์: ํต์ฌ ์น ์งํ, ๋ฆฌ์์ค ํ์ด๋ฐ, ์ฌ์ฉ์ ์ง์ ๋ฉํธ๋ฆญ์ ๋ํด ํ๋์ฉ). ์ด๋ ๊ฒ ํ๋ฉด ์ฝ๋ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง ๊ด๋ฆฌ์ฑ์ด ํฅ์๋ฉ๋๋ค.
- ์ฑ๋ฅ ์ค๋ฒํค๋ ์ดํด: API๋ ์ค๋ฒํค๋๊ฐ ๋งค์ฐ ๋ฎ๋๋ก ์ค๊ณ๋์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ณผ๋ํ ๊ณ์ฐ์ ์ํํ๋ ๋งค์ฐ ๋ณต์กํ ์ฝ๋ฐฑ ํจ์๋ ์ฑ๋ฅ์ ์ ์ฌ์ ์ผ๋ก ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ๊ด์ฐฐ์ ์ฝ๋ฐฑ์ ๊ฐ๊ฒฐํ๊ณ ํจ์จ์ ์ผ๋ก ์ ์งํ์ญ์์ค. ๋ชจ๋ ๊ณผ๋ํ ์ฒ๋ฆฌ๋ฅผ ์น ์์ ์๋ก ์ฐ๊ธฐํ๊ฑฐ๋ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐฑ์๋๋ก ๋ณด๋ด ์ฒ๋ฆฌํ์ญ์์ค.
๊ฒฐ๋ก : ์ฑ๋ฅ ์ฐ์ ๋ฌธํ ๊ตฌ์ถ
Performance Observer API๋ ๋จ์ํ ๋๊ตฌ ๊ทธ ์ด์์ ๋๋ค. ์น ์ฑ๋ฅ์ ์ ๊ทผํ๋ ๋ฐฉ์์ ๊ทผ๋ณธ์ ์ผ๋ก ๋ฐ๊ฟ๋๋ค. ๋ฐ์์ ์ด๊ณ ์ผํ์ฑ ์ธก์ ์์ ์ ์ธ๊ณ ์ฌ์ฉ์์ ์ง์ ํ ์ญ๋์ ์ธ ๊ฒฝํ์ ๋ฐ์ํ๋ ์ฌ์ ์๋ฐฉ์ ์ด๊ณ ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง์ผ๋ก ์ฐ๋ฆฌ๋ฅผ ์ด๋์ํต๋๋ค. ํต์ฌ ์น ์งํ, ๊ธด ์์ , ๋ฆฌ์์ค ํ์ด๋ฐ ๋ฐ ์ฌ์ฉ์ ์ง์ ๋ฉํธ๋ฆญ์ ์บก์ฒํ๋ ์์ ์ ์ด๊ณ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํจ์ผ๋ก์จ ๊ฐ๋ฐ์๋ ์๋น์์ ์ฌ์ฉ์์๊ฒ ์ํฅ์ ๋ฏธ์น๊ธฐ ์ ์ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํ๊ณ ํด๊ฒฐํ ์ ์์ต๋๋ค.
Performance Observer API๋ฅผ ์ฑํํ๋ ๊ฒ์ ๋ชจ๋ ๊ฐ๋ฐ ํ์์ ์ฑ๋ฅ ์ฐ์ ๋ฌธํ๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํ ์ค์ํ ๋จ๊ณ์ ๋๋ค. ์ค์ํ ์ฌํญ์ ์ธก์ ํ ์ ์๋ค๋ฉด ์ค์ํ ์ฌํญ์ ๊ฐ์ ํ ์ ์์ต๋๋ค. ์ง๊ธ ๋ฐ๋ก ์ด๋ฌํ ๊ด์ฐฐ์๋ฅผ ํ๋ก์ ํธ์ ํตํฉํ์ญ์์ค. ์ ์ธ๊ณ ์ด๋์ ์๋ ์ฌ์ฉ์๋ ๋ ๋น ๋ฅด๊ณ ์ํํ๋ฉฐ ์ฆ๊ฑฐ์ด ๊ฒฝํ์ ๊ฐ์ฌํ ๊ฒ์ ๋๋ค.