๐๋ณธ ๋ฌธ์๋ Optimize JavaScript execution์ ๋ฒ์ญํ ๋ฌธ์์ด๋ฉฐ ์ค์ญ, ์์ญ์ด ์กด์ฌํ ์ ์์ต๋๋ค. ์ด์ธ์ ์ถ๊ฐ์ ์ผ๋ก ์ฐธ๊ณ ํ Reference๋ ๋ฌธ์ ๋ง์ง๋ง์ ๊ธฐ์ฌํด ๋์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ Style์ ์ง์ ์กฐ์ํ๊ฑฐ๋, ๋ฐ์ดํฐ ์ ๋ ฌ ํน์ ๊ฒ์๋ฑ์ ์์ ์ ํตํด์ ์๊ฐ์ ์ธ ์ ๋ฐ์ดํธ๋ฅผ ๋ง๋ญ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์๋ฐ์คํฌ๋ฆฝํธ์ ์คํ ์๊ฐ์ด ๊ธธ๊ฑฐ๋ ํน์ ์คํ๋๋ ํ์ด๋ฐ์ด ์์ข์ ๊ฒฝ์ฐ ํผํฌ๋จผ์ค ์ด์๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ๊ฐ๋ฅํํ ์ด ์ํฅ์ ์ต์ํํด์ผ ํฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ ์์ฑํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ ์ค์ ์คํ๋๋ ์ฝ๋์๋ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์, ์๋ฐ์คํฌ๋ฆฝํธ ์ฑ๋ฅ์ ๋ถ์ํ๋ค๋ ๊ฒ์ ์์ ์ ๊ฐ๊น์ด ํ์์ผ ์ ์์ต๋๋ค. ๋ชจ๋ ๋ธ๋ผ์ฐ์ ๋ JIT ์ปดํ์ผ๋ฌ๋ฟ๋ง ์๋๋ผ ์ฌ๋ฌ ์ต์ ํ์ ํธ๋ฆญ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, ์ฝ๋์ ๋์์ ํฌ๊ฒ ๋ฐ๊ฟ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์ข ๋ ์ ์คํ๋ ์ ์๋๋ก ๋๋ ๋ช ๊ฐ์ง ๋ถ๋ช ํ ๋ฐฉ๋ฒ์ด ์กด์ฌํฉ๋๋ค.
๐ค 1๋ฒํ๊ณ ๊ฐ์ ์ด์ผ๊ธฐ๊ฐ์ต๋๋ค. ์๋ง rAF์ ์ฝ๋ฐฑ ํจ์๋ micro-task queue์ enqueue๊ฐ ๋๊ณ , ์ฌ๋ฌ ํ๋ ์์ ๊ฑธ์ณ์ DOM ๋ณํ๊ฐ ์ผ์ด๋๋ ๊ฒฝ์ฐ๋ animation ์ํฉ์ ์ด์ผ๊ธฐํ๋ ๋ฏ ํฉ๋๋ค. rAF๋ฅผ ์ฌ์ฉํ๋ผ๋ ์๋ฏธ๊ฒ ์ฃ ?
rAF๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ํ๋ ์์ ์์ ์ง์ ์์ ํธ์ถํ์ฌ Frame loss๋ฅผ ์ต์ํํฉ๋๋ค.
/**
* If run as a requestAnimationFrame callback, this
* will be run at the start of the frame.
*/
function updateScreen(time) {
// Make visual updates here.
}
requestAnimationFrame(updateScreen);
setTimeout์ด๋ setInterval์ ์ฌ์ฉํ์ฌ ์๊ฐ์ ์ธ ์ ๋ฐ์ดํธ๋ฅผ ํ๋ คํ๋ ๊ฒฝ์ฐ, ์ฝ๋ฐฑ ํจ์๊ฐ ํ๋ ์ ๊ฐ๊ฒฉ์ ๋๋คํ ์ง์ ์์ ํธ์ถ๋๋ฉฐ, ์ต์ ์ ๊ฒฝ์ฐ, ๋ค์ ํ๋ ์์ด ๋ณด์ฌ์ง๊ธฐ ๋ฐ๋ก ์ง์ ์ ํธ์ถ๋์ด Frame Loss๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
jQuery๋ ํ๋๋ ์ ๋๋ฉ์ด์ ์ ์ํด setTimeout์ ์ฌ์ฉํ์ผ๋, version3์ ์ค๋ฉด์ rAF๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ์ต๋๋ค. ๋ง์ฝ ์๋ ๋ฒ์ ์ jQuery๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, rAF๋ฅผ ์ฌ์ฉํ๋ version3์ผ๋ก์ ์ ๋ฐ์ดํธ๋ฅผ ๊ฐ๋ ฅํ๊ฒ ๊ถ๊ณ ๋๋ฆฝ๋๋ค.
๐ค setTimeout์ด๋ setInterval์ ์ฝ๋ฐฑ ํจ์๊ฐ ๋ชจ๋ํฐ ์ฃผ์ฌ์จ๋ณด๋ค ๋ ๋น ๋ฅด๊ฒ ์คํ์ด ๋๋ค๋ฉด, ์ด ์ญ์๋ Frame Loss๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ๊ฐ๋ น 16.7ms์ Frame ๊ฐ๊ฒฉ์ ๊ฐ๋ ๋ชจ๋ํฐ์์, 4.7ms๋ก setTimeout์ ํธ์ถํ๋ ๊ฒฝ์ฐ, 4๋ฒ์ด ํธ์ถ๋์ด๋ 3๋ฒ์ Loss๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
ํ์ง๋ง rAF์ ๊ฒฝ์ฐ, ํธ์ถ ์๊ฐ์ด ๋ชจ๋ํฐ ์ฃผ์ฌ์จ์ ์ํด ๊ฒฐ์ ๋๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ Frame Loss๋ ๊ฑฑ์ ํ์ง ์์๋ ๋๋ฉฐ, repaint ์ด์ ์ ํธ์ถ๋๋ ๊ฒ์ ๋ณด์ฅํฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ธ๋ผ์ฐ์ ์ main thread์์ ์คํ๋๋ฉฐ, ์คํ์ผ ๊ณ์ฐ, ๋ ์ด์์, ํ์ธํธ ๋ฑ์ด ์ฐจ๋ก๋๋ก ์คํ๋ฉ๋๋ค. ๋ง์ฝ ์๋ฐ์คํฌ๋ฆฝํธ ์คํ ์๊ฐ์ด ๋๋ฌด ๊ธธ๋ค๋ฉด, ์๋ฐ์คํฌ๋ฆฝํธ ์ดํ์ ์์ ๋ค์ด ์ฐจ๋ก๋๋ก block์ด ๋์ด frame loss๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ธ์ , ๊ทธ๋ฆฌ๊ณ ์ผ๋ง๋ ์ค๋ซ ๋์ ์คํ์ํฌ ๊ฒ์ธ์ง์ ๋ํด์ ์ ๋ต์ ์ผ๋ก ์ ๊ทผํด์ผ ํฉ๋๋ค. ์คํฌ๋กค๊ณผ ๊ฐ์(?) ์ ๋๋ฉ์ด์ ์ด ์กด์ฌํ๋ค๋ฉด, ์ด์์ ์ผ๋ก๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ์คํ ์๊ฐ์ด 3~4ms ์ด๋ด์ฌ์ผ ํฉ๋๋ค. ๋ง์ฝ ์ด ์๊ฐ๋ณด๋ค ๊ธธ์ด์ง๊ฒ ๋๋ค๋ฉด, frame loss๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ๋ง์ฝ ์ ํด ์๊ฐ์ ์๋ค๋ฉด, ์กฐ๊ธ ๋ ์ฌ์ ๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.(์คํฌ๋กค ์ ๋๋ฉ์ด์ ์ ๋ํ ๋ด์ฉ๊ฐ์๋ฐ ํด์์ด ์๋๋ค์)
๋ฐ์ดํฐ ์กฐ์ ํน์ ํ์, ์ ๋ ฌ๊ณผ ๊ฐ์ด DOM์ ์ ๊ทผํ์ง ์๋ ๊ฒฝ์ฐ๋ผ๋ฉด Web Worker์๊ฒ ๊ณ์ฐ ์์ ์ ๋งก๊ธธ ์ ์์ต๋๋ค.
var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);
// The main thread is now free to continue working on other things...
dataSortWorker.addEventListener('message', function(evt) {
var sortedData = evt.data;
// Update data on screen...
});
Web Worker๋ DOM ์ ๊ทผ ๊ถํ์ด ์์ผ๋ฏ๋ก, DOM์ ์ ๊ทผํด์ผํ๋ ์์ ์ ๋งก๊ธฐ๋ ๊ฒ์ ์ ํจํ์ง ์์ต๋๋ค. (๐ฅํด์์ด ์ด๋ ต๋ค์) Where your work must be on the main thread, consider a batching approach, where you segment the larger task into micro-tasks, each taking no longer than a few milliseconds, and run inside of requestAnimationFrame handlers across each frame.
์ด ๋ฐฉ์์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ์งํ๋ฅ ์ ์ ์ ์๊ฒ ๋ณด์ฌ์ค์ผ๋ก์จ ์์ ์ด ์งํ๋๊ณ ์์์ ์๋ ค์ฃผ์ด์ผ ํฉ๋๋ค. ์ด์ฐ๋๊ฑด ์ด ์ ๊ทผ ๋ฐฉ๋ฒ์, ์ฑ์ main thread๋ฅผ ์ข ๋ freeํ๊ฒ ๋ง๋ค๊ณ , ์๋ต์ฑ์ ๋์ด๋๋ฐ ๋์์ ์ค๋๋ค.
๐ค ์๋ง๋ renderer process ๋ด๋ถ์ ์ฌ๋ฌ ์ค๋ ๋ ์ค, ์ด๋ฒคํธ๋ ๋ ๋๋ง์ ๋ด๋นํ๋ main thread๊ฐ ๋๋ฌด ๋ฌด๊ฑฐ์์ง๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด, Web Worker๋ฅผ ์ด์ฉํด์ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ณต์กํ ์ฐ์ฐ์ ๋ค๋ฅธ thread์์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ๋ค. ์ ๋๋ก ์ดํดํ๋ฉด ๋์ง ์์๊น ์ถ์ต๋๋ค. ๊ด๋ จํ ์ถ๊ฐ ๋ด์ฉ์ ์๋ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์๋ฉด ๋ ๋ฏ ํฉ๋๋ค.
Web Worker
๋ธ๋ผ์ฐ์ ํ๋ก์ธ์ค
Minimize main thread work
Main Thread
ํ๋ ์์ํฌ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ํน์ ๋น์ ์ ์ฝ๋๋ฅผ ํ๊ฐํ ๋, ํ๋ ์ ๋จ์๋ก Javascript๋ฅผ ์คํํ๋๋ฐ ๋๋ ๋น์ฉ์ ํ๊ฐํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๊ฒ์ ํนํ๋ ์ฑ๋ฅ์ ์น๋ช ์ ์ผ ์ ์๋ transition์ด๋ scrolling ์ ๋๋ฉ์ด์ ์์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
Chrome DevTools๋ ์ด๋ฌํ ์๋ฐ์คํฌ๋ฆฝํธ ๋น์ฉ์ ์ธก์ ํ๋๋ฐ ๋์์ ์ค๋๋ค.
์ฌ๊ธฐ์ Main Section์ ์๋ฐ์คํฌ๋ฆฝํธ ํธ์ถ์ ๋ํ Flame Chart๋ฅผ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์, ์ฝ๊ฒ ์ด๋ค ํจ์๊ฐ ํธ์ถ๋๊ณ , ์ผ๋ง๋ ์ค๋ซ๋์ ์คํ๋๋์ง ์ ์ ์์ต๋๋ค.
์ด๋ฌํ ์ ๋ณด๋ฅผ ํ ๋๋ก ์ฑ์์ ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์ฑ๋ฅ์ ์ผ๋ง๋ ์ํฅ์ ๋ผ์น๋์ง ํ์ธํ ์ ์์ผ๋ฉฐ, ์คํ์ ๋ง์ ์๊ฐ์ด ์์๋๋ ํจ์๋ฅผ ์ฐพ์์ ์์ ํ ์ ์์ต๋๋ค. ์์ ๋งํ๋ฏ์ด, ์ฐ๋ฆฌ๋ ์คํ ์๊ฐ์ด ๊ธด ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋, ๋ถ๊ฐ๋ฅํ๋ค๋ฉด Web Worker๋ก ์ด๋์์ผ์ผ ํฉ๋๋ค.
์ด๋ค ๊ฐ์ฒด์ offsetTop์ ๊ตฌํ๋ ๊ฒ์ด, getBoundingClientRect()๋ฅผ ๊ณ์ฐํ๋ ๊ฒ ๋ณด๋ค 100๋ฐฐ ๊ฐ๋ ๋น ๋ฅด๋ค๋ ๊ฒ์ ์๊ณ ์๋์? ์๊ณ ์์ผ๋ฉด ์ข์์ง๋ ๋ชจ๋ฅด์ง๋ง, ์ด๋ฌํ ํจ์๋ค์ ํ๋ ์๋น ํธ์ถ๋๋ ํ์๊ฐ ๋งค์ฐ ์ ๊ณ , ์ด๋ฌํ ๋น์ฉ์ ์๊ปด๋ดค์ ๊ณ ์ ms๋จ์๋ฐ์ ์๋ผ์ง ๋ชปํฉ๋๋ค. ๋๋ฌด microํ๊ฒ ์ต์ ํํ๋ ค ํ๋ ๊ฒ์ ๋นํจ์จ์ ์ผ ์ ์์ต๋๋ค.
๊ฒ์๊ณผ ๊ฐ์ด ์ฐ์ฐ ๋น์ฉ์ด ๋ง์ด ๋๋ ์ฑ์ ์ค๊ณํ๋ค๋ฉด, ํ๋ ์ ํ๋๋น ๋ง์ ์ฐ์ฐ์ด ๋ค์ด๊ฐ๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ์กฐ์ธ์ด ์์ธ์ผ ์ ์์ต๋๋ค
CPU ์์์ ๊ณ ๋ คํฉ๋๋ค(CPU Optimization). ๋ค๋ฅธ ํญ์ ์๋ ๊ฒฝ์ฐ, rAF๋ด์ ์ฝ๋ฐฑ ํจ์ ํธ์ถ์ ๋ฉ์ถ๊ฒ ๋ฉ๋๋ค.
What requestAnimationFrame is ?
Why requestAnimationFrame is better than setTimeout and setInterval in HTML5
Window.requestAnimationFrame