지난주 금요일에 다녀온 DevOn 에서 가장 인상 깊었던 Improve Your Javascript 세션 후기.

Javascipt가 느리다고 F**c! Sh*t! 거릴게 아니라  왜 느린지? 어떻게 빠르게 만들 수 있는지?

한번쯤 생각해보게 만드는 세션!

참고 : http://devon.daum.net/2011/pdf/F-4-improve_your_javascript.pdf
        
http://www.youtube.com/watch?v=mHtdZgou0qU

Javascript를 빠르게 할 수 있는 4가지 TIP!

1. 2번 이상 사용되는 Global or 상위레벨 변수들은 Local에 재선언한 뒤 사용.

2. Minimize DOM Access.

3. Avoid Reflow.

4. Tune loop.

1. 변수를 Local에 재선언한 뒤 사용!

     Javascript Engine은 변수를 Look up할 때 Scope chain을 이용하는데 현재 범위에 선언되어 있는
      변수들이 Scope chain에서 가장 먼저 발견되기 때문!
      실제 동작하는 방식은 아래 그림과 같다.
 

Scope Chain을 이용하여 변수를 찾는 과정

– Before –
document.getElementById(‘1’);
document.getElementById(‘2’);

– To Be –
var doc = document;
doc.getElementById(‘1’);
doc.getElementById(‘2’);

위와 같은 방법으로 자주 사용하는 global 변수들은 local에 재정의 한 뒤 사용하라고 하는데

실제로 속도 측정을 해보면 브라우저가 너무 좋아서 그런지 몰라도 그닥? 별 차이를 보이지 않습니다. ㅠㅠ  

2. Minimize DOM Access
     Javascript와 DOM은 서로 다른 Engine에서 처리되기 때문에 Javascipt에서 DOM을
      Access하는 건 느릴 수 밖에 없다고 합니다.

JS와 DOM은 서로 다른 Engine에서 처리된다.

     아래 표는 실제로 가장 많은 시간이 소요되는 API들 입니다. 대부분이 DOM API로 채워져 있습니다.
     (개인적으로 자주 사용하는 appendChild, removeChild, getElementById 등이 상위에 있네요. -_-;)

F**king Slow APIs.jpg

     실제로 HTML내에 15개의 div를 선언한 뒤 아래 2개의 함수의 수행시간을 측정해보면 10배 이상 차이가 나는걸
      확인할 수 있습니다. 아마 페이지의 복잡성이 증가할수록 속도차이는 더 증가할 것 같습니다.

– Before –
function slowDomNodeLoop(values) {
var divs = document.getElementsByTagName(“div”);
for (var i=0; i<divs.length; i++) {

process(values[i]);
}
}

– To Be –
function fastDomNodeLoop(values) {
var divs = document.getElementsByTagName(“div”);
for (var i=0, len=divs.length; i<len; i++) {
process(values[i]);
}
}


속도 차이가 발생하는 이유는 divs.length가 DOM Object이기 때문입니다.
 
이걸 divs.length를 Local 변수로 재선언한 뒤 Loop에서 참조하며 ‘겁나’ 빨라집니다.

3. Avoid Reflow
     What is Reflow? : Document내에 element들의 위치를 계산하는 작업을 의미합니다.
                               Page가 복잡해질수록 그 대가는 처절해집니다. 따라서 우리는 Reflow를 발생시키는
                               원인들을 차단한 필요가 있습니다!
      

      Reflow가 발생하는 원인!
       1) page render initially
       2) window is resized
       3) visible DOM Elements are added or removed
       4) element change position / size
       5) text changes
       6) image replaced

 
      Reflow를 줄일 수 있는 TIP 2개!
 

      1) CSS의 속성을 변경하는 대신 Class Type을 변경!
 

– Before, with 3 reflows –
element.style.height = “100px”;    <- Reflow
element.style.display = “block”;   <- Reflow
element.style.fontSize = “130%”;   <- Reflow

– To Be, only one reflow –

.active {
height: 100px;
display: block;
font-size: 130%;
}
element.className = “active”;    <- Reflow 

      2) DocumentFragment 이용!
– Before – 

function makeListWithReflow() {
var list = document.getElementById(“list”);
for (var i=0; i<50; i++) {
var item = document.createElement(“li”);
item.innerHTML = “Option # ” + (i+1) + new Date().getTime();
// Reflows are occured when elements are added.
list.appendChild(item);
}

}

 

 

– To Be – 
function makeListAvoidReflow() {
var list = document.getElementById(“list”);
var fragment = document.createDocumentFragment();
for (var i=0; i<50; i++) {
var item = document.createElement(“li”);
item.innerHTML = “Option # ” + (i+1) + new Date().getTime();
// No Reflow cause fragment is non visible element.
fragment.appendChild(item);
}
// Only 1 reflow.
list.appendChild(fragment);

4. Tune loop
     일반적으로 사용하는 Loop를 아래와 같이 약간만 수정하면 50%나 빨라진다고 하는데
     실제로 속도를 체크해보면 그닥? JS Engine이 너무 좋아서 차이가 안나는 걸까?

     –  Before  –

     for (var i=0; i<items.length; i++) {

        process(items[i]);

     

}

     

–  To Be, less compare  –

     var k = items.length – 1;

     do {

        process(items[k]);

     } while(k–);

아! 개인적으로 Chrome/FF에서 시간 측정을 해봤는데 2번과 3번은 실제로 차이가 좀 나는거 같은데

1번과 4번은 별 차이가 없네요. -_-;; 부끄럽습니다. V8과 TraceMonkey가 너무 좋은거라 생각하고 있음.

이상!