Javascript 성능 향상 코딩 팁

JavaScript

자바스크립트 성능 측정 방법

  1. console.time
console.time(0);
// 여러가지 로직 수행
console.timeEnd(0);

console.time('t1');
// 다양한 로직 수행
console.timeEnd('t1');

0: 7468.280029296875 ms
  1. performance.now
var t1 = performance.now();
// 여러가지 로직 수행
var t2 = performance.now();
console.log("소요 시간: " + (t2 - t1) + 'ms')

소요 시간: 5976.399999976158ms

console.time 이 더 사용하기 쉬우나 비표준이므로 디버깅 용도로만 사용할 것. 프로덕션 환경에서는 사용하지 않는 것이 좋다.

performance.now 는 사용하기는 번거롭지만 표준이며, one thousandth of a millisecond 의 정확도를 가지고 있어 정밀한 측정이 가능하다.

성능 향상을 위한 코딩

변수 선언을 한번에 하는 방법

// 한번에 여러개의 변수를 할당할 수 있다.
const a = 1,
			b = 2,
			c = 3;

Loop 성능 향상 방법

const person = {
	home : [
		{ addr:'서울', country : 'ko'}, 
		{ addr:'대전', country : 'ko'}, 
		{ addr:'대구', country : 'ko'}, 
		{ addr:'부산', country : 'ko'}, 
		{ addr:'파리', country : 'fr'}  
	]
}

for (let i=0; i < person.home.length; i++){
	console.log(person.home[i]);
}
// 위 코드는 아래와 같은 단계를 거침
// 1) i값 탐색
// 2) person 객체 탐색
// 3) home 속성 탐색
// 4) home 속성의 인덱스 탐색
// 5) length 프로퍼티 검색
// for 문을 수행하는 동안 위 5단계를 계속 반복

// => 아래와 같이 향상
let len = person.home.length;	// length 1회 접근
for (let i=0; i < len; i++){
	console.log(person.home[i]);
}

// => 아래와 같이 향상
for (let i=0, len=person.home.length; i < len; i++){ // 전역으로 선언하지 않아 메모리 절감
	console.log(person.home[i]);
}

// => 아래와 같이 향상
let list = person.home;  // list에 person 객체의 home 속성을 미리 할당.
for (let i=0, len = list.length; i < len ; i++){
	console.log(list[i]);  // 반복할 때 마다 person 객체의 home 속성에 접근할 필요 없음.
}

// => chatGPT 솔루션
person.home.forEach(item => {
	console.log(item);
});

정규표현식 Loop 성능 향상

for (let i = 0; i < 100; i++) {     
	str[i].replace(/^\d{3}-\d{3,4}-\d{4}$/, "");
}
// 정규 표현식은 컴파일 이후 처리가 필요. 100회의 반복적인 컴파일을 수행하게 된다.

// => 아래와 같이 향상
let reg = /^\d{3}-\d{3,4}-\d{4}$/; // 1회만 컴파일
for (let i = 0; i < 100; i++) {     
	str[i].replace(reg, "");
}

조건 비교 연산 성능 향상

let value = 3;

if (value === 1) {
	...
} else if (value === 2) {
	...
} else if (value === 3) {   // 맨 위부터 순차적으로 비교
	...
}

// => 아래와 같이 향상
switch (value) {
	case 1 :
		...
	case 2 :
		...
	case 3 :  // 3으로 바로 진입
		... 
}

스크립트 선언을 통한 성능 향상

// 브라우저의 렌더링 엔진은 HTML문서를 한줄 한줄 순차적으로 파싱하며 DOM을 생성
<html>
	<head>
		<meta charset="UTF-8">  // 여기까지 파싱했고...
		<link rel="stylesheet" href="style.css"/> 
		<style type="text/css">  
		...
		// link 태그를 만나면 CSS파일을 서버에 요청한 후 응답받아 CSS파싱을 시작.
		// style 태그는 상단에 선언하여 DOM 렌더링이 다시 이루어지지 않도록 하는 것이 좋다.
		</style>
	</head>
	<body>
		...
		<script type="text/javascript">  // 가급적 최하단에 script 선언
			...   
			// script 태그를 만나면 DOM 파싱을 중단하고 script 엔진에 제어권을 넘긴다.
			// DOM이 완성되지 않은 상태에서 DOM Api를 통해 DOM을 조작하면 에러가 발생할 수 있음.
			// 자바스크립트의 로딩/파싱/실행으로 인해 페이지의 로딩 시간이 길어질 수 있다.
			// 스크립트 처리가 지연되는 경우 사용자는 빈 화면 또는 미완성된 화면을 볼 수 있다.
		</script>
	</body>
	</html>

정리하면 아래와 같다.

브라우저 렌더링은 HTML 파서, CSS 파서, Javascript 엔진이 처리한다.

  1. HTML파서가 한줄 한줄 파싱
  2. link 또는 style 태그를 만나면 CSS파서가 파싱
  3. 1, 2 는 병렬적으로 처리된다.
  4. 1, 2 는 머지 되어 Painting 이 이루어 진다.
  5. 스크립트가 실행되는 동안 문서의 파싱은 중단된다. 스크립트가 외부에 있는 경우 우선 네트워크로부터 자원을 가져와야 하는데 이 또한 실시간으로 처리되고 자원을 받을 때까지 파싱은 중단된다.

결론적으로 사용자에게 빠르게 화면을 보여주기 위해서 파싱 중단을 야기하는 Script 태그는 하단에 배치하는것이 바람직하다.

Reflow 를 최소화

DOM의 변경으로 다시 렌더 트리를 재생성 하는 과정을 Reflow, 재생성된 렌더 트리를 다시 그리는걸 Repaint(or Redraw) 라고 한다.

var target = document.getElementById('container');
for (var i = 0 ; i < 1000; i++){
	var div = document.createElement('div');
	div.innerText = i;
	target.appendChild(div);  // 1000번의 reflow 발생
}

// => 아래와 같이 향상
var fragment = document.createDocumentFragment();
for (var i = 0 ; i < 1000; i++){
	var div = document.createElement('div');
	div.innerText = i;
	flagment.appendChild(div);
}
var target = document.getElementById('container');
target.appendChild(flagment);  // 1번의 reflow 발생
다음 글: HUGO 사이트 배포를 위한 배치 파일 생성 이전 글: Javascript find, findIndex, filter

See Also