전역 변수에 대한 접근은 모든 브라우저에서 느려진다.
function initUI() { var bd = document.body; var links = document.getElementsByTagName("a"); var i = 0; var len = links.length; while (i < len) { update(links[i++]); } document.getElementById('go-btn').onclick = function() { start(); }; bd.className = 'active'; }
위의 예제에서는 document
객체를 3번이나 참조하므로 느려진다.
그렇기 때문에 전역변수
를 로컬 변수로 변환해서 사용하면 성능이 향상된다.
// 변경 로직 function initUI() { var doc = document; var bd = doc.body; var links = doc.getElementsByTagName("a"); var i = 0; var len = links.length; while (i < len) { update(links[i++]); } doc.getElementById('go-btn').onclick = function() { start(); }; bd.className = 'active'; }
클로저를 사용할 때는 항상 주의를 해야 한다.
동적 코드를 생성하는 eval()
함수의 사용은 자제 하는게 좋다.
멤버가 깊이 중첩될수록 데이터 접근이 더 느려진다.
windows.location.href.toString() 보다 window.location.href 를 더 빨리 해석한다.
// Bad window.location.href // good location.href
DOM이 하나의 대륙이고 자바스크립트가 다른 대륙인데, 두 대륙을 아주 긴 다리로 연결했다고 생각하면 이해하기 쉽다.
아래의 로직은 innerHTML 값을 읽기 위해 한번 접근하고 그 값을 수정하기 위해 한번 더 DOM 에 접근한다.
// Bad function innerHTMLLoop() { for (var count = 0; count < 15000; count++) { document.getElementById('here').innerHTML += 'a'; } } // Good function innerHTMLLoop() { var content = ''; for (var count=0; count < 15000; count++) { content += 'a'; } document.getElementById('here').innerHTML += content; }
예기치 못한 무한루프
- document.getElementsByName()
- document.getElementsByClassName()
- document.getElementsByTagName()
HTMLCollection 객체에 접근하는 함수는 호출 될 때 마다 DOM 모델에서 모든 객체를 대상으로 하므로 아래의 코드는 무한 루프에 빠진다.
var allDivs = document.getElementsByTagName('div'); for (var i=0; i<allDivs.length; i++) { document.body.appendChild(document.createElement('div')); }
아래의 코드는 HTMLCollection이 아니므로 반환된 노드는 문서 구조를 동적으로 변경하지 않는다.
var elements = document.querySelectorAll('#menu a');
알고리즘
- for 문
- while 문
- do while문
- for-in 문
위의 4가지 반복문중에서 for-in 문의 성능이 가장 낮다. 객체에 많은 속성이 포함되어 있다면 for-in 문은 사용을 자제해야 한다.
루프의 순서
일반적인 프로그래밍 언어에서는 루프의 순서를 거꾸로 하기만 해도 성능이 향상된다.
실행 조건을 평가 할 때 단순히 0과 비교.
for (var i=0; i<items.length; i++) { process(items[i]); } // Better for (var i=items.length; i > 0; i--) { process(items[i]) }
조건문
- if-else
- switch
조건이 적을 때는 if-else 구문을 사용하고 조건이 많은 경우에는 switch 구문을 사용한다. if-else 구문은 조건이 많아 질 수록 느려진다.
if-else 구문을 사용할 때도 자주 발생하는 조건을 우선적으로 적으면 성능이 향상된다.
문자열과 정규 표현식
정규 표현식의 효율성을 올리는 방법
- 실패할 거라면 되도록 일찍 실패하게
- 단순하고 꼭 필요한 토큰으로 시작
- or 연산자를 줄이고, 써야 한다면 적용 범위를 작게
- 정규식을 뼌수에 할당해서 재사용
- 복잡한 정규식을 간단한 조각으로 분리
응답성 좋은 인터페이스
- 자바스크립트 코드가 100밀리초 이상으로 실행되서는 안된다.
- 오래 걸리는 작업을 타이머로 분리해서 실행한다.
- 큰 JSON 문자열의 파싱 작업은 web worker 를 이용해서 별도로 처리하도록 한다.