Pages

2014년 1월 29일 수요일

[JAVASCRIPT] 자바스크립트 속도 향상 시키기

자바스크립트 성능 이슈

1. 스코프 관리
  • 식별자 해석
    • 지역 변수가 빠르다.
    • 체인이 깊어질 수록 더 느려진다.
  • 스코프 체인 증가
    • with 문
    • try-catch 문의 catch 절
    • -> 둘 다 스코프 체인의 앞에 객체를 추가한다.
  • 권장사항
    • 지역 변수에 out-of-scope 변수를 저장하라 (특히 전역 변수)
    • with 문을 피하라
      - 스코프 체인에 다른 객체를 추가한다. 따라서 지역 함수 변수들은 바로 한 단계 멀어진다.
      - 대신에 지역 변수를 사용하라
    • try-catch 문을 조심히 사용하라
      - catch 절 또한 스코프 체인이 증가시킨다.
    • 클로저closures를 조금만 사용하라
      - 변수를 선언할 때 var를 잊지 말아라
2. 데이터 접근
  • 데이터 접근 성능
    • 문자(literal)나 지역변수로 부터 데이터 접근이 가장 빠르다. 문자와 지역 변수 사이에 차이는 대부분의 경우에 무시해도 된다.
    • 객체 속성이나 배열 아이템으로 부터 데이터 접근이 더 비싸다. Accessing data from an object property or array item is more expensive
      - 이것은 브라우저에 의해 결정된다.
    ※ 챠트(동영상 17:19) 내용으로 보아 Firfox 3.1, Chrome2, Safari4 이상은 literal, local과 데이터 접근 속도가 0에 가까운 정도로 매우 빠름 (Opera10은 차이는 작지만 데이터 접근 속도는 20~30사이, IE7,8은 차이가 30정도로 크고 접근 속도 자체가 40이상)
  • 속성 깊이
    • object.name < object.name.name
    • 깊어진 속성일수록 검색하는 시간이 더 오래 걸린다. (IE7,8이 가장 가장 느려짐)
  • 속성 표기법
    • object.name 과 object["name"] 사이에 다른 점은?
      - 일반적으로 없다.
      - 예외 : Safari에서는 도트 표기법이 더 빠르다.
  • 권장사항
    • 이것들을 지역 변수에 저장하라.
      - 한 번 이상 접근하는 객체 속성
      - 한 번 이상 접근하는 배열 아이템
    • 속성/배열 아이템 색인 깊이를 최소화하라.
    function process(data){
     if(data.count>0){
      for (var i=0;i<data.count;i++){
      processdata(data.item[i]);
      }
     }
    }
    아래와 같이 변경한 결과 FF – 5%, Safari -10%, IE -33% 속도 향상
    function process(data){
    
    var count = data.count,
        item = data.item; //지역 변수로 지정
    
     if(data.count>0){
      for (var i=0;i<data.count;i++){
       processdata(data.item[i]);
      }
     }
    }

3. 반복문
  • ECMA-262, 3rd Edition
    - for, do-while, while
    for in
  • 문제가 무엇인가요?
    • ?반복 당 작업 종료 양(Amount of work done per iteration) – terminal condition evaluation과 증가/감소를 포함
    • 반복 횟수
    • 이것은 루프 타입에 따라 바뀌지 않는다.
  • 반복문 고치기
    • 반복 당 작업량을 줄여라 Decrease amount of work per iteration
    • 반복 횟수를 줄여라
  • 쉽게 고치기
    - 객체 속성/배열 아이템 검색을 제거해라 
    for (var i=0;i<values.length;i++){
     process(values[i]);
    }
    
    var j=0;
    do { process(values[j++]); } while ( j < values.length);
    아래와 같이 지역 변수에 저장하여 반복 조건에서 객체 속성 검색을 제거
    var len = values.length;
    
    for (var i=0;i<len;i++){
     process(values[i]);
    }
    
    var j=0;
    do { process(values[j++]); } while ( j < len);
  • 제어 조건과 제어 변수 변경을 결합하라 Combine control condition and control variable change
  • 속도를 위해 회피할 것들
    • ECMA-262, 3rd Edition : for-in
    • ECMA-357, 2nd Edition : for-each
    • ECMA-262, 5th Edition : array.forEach()
    • 함수 기반 반복문: jQuery.each(), Y.each(), $each,Enumerable.each()
4. DOM
  • HTMLCollection Objects
    • document.images, document.forms, etc.
    • getElementsByTagName() – 도큐먼트의 모든 div엘리먼트를 요청하면 도큐먼트는 div엘리먼트에 변경이 발생할 때 마다 업데이트 하므로 계속해서 요청이 발생한다.
    • getElementsByClassName()
    • 배열처럼 보이지만 아닌 것들
      - 괄호 표기법
      - length 속성
    • 특정 쿼리의 결과를 나타낸다
    • 쿼리는 객체에 접근할 때 마다 매 번 재실행 된다.
      - length와 특수한 항목에 접근하는 것을 포함
      - 동일한 배열에 접근하는 것 보다 많이 느리다.
      - 예외:Opera, Safari
    var items = [{},{},{}, ...,{}];
    for (var i=0; i<items.length;i++){ }
    
    var divs = document.getElementsByTagName("div");
    for (var i=0; i<divs.length;i++){ }
    => FF 15배, Chrome 53배, IE 68배 느려짐
    아래와 같이 지역 변수에 저장하여 변경하면
    var items = [{},{},{}, ...,{}];
    for (var i=0, len=items.length ; i< len ;i++){ }
    
    var divs = document.getElementsByTagName("div");
    for (var i=0, len=divs.length ; i< len ;i++){ }
    => 느려지지 않음
    • 속성 접근을 최소화하라
      - 자주 사용하는 경우 지역 변수에 length와 항목들을 저장하라
      - 자주 순차적으로 항목들에 접근하려면 규칙적인 배열 안에 복사해라
    fuction array(items){
     try{
      return Array.prototype.concat.call(items);
     } catch(ex){
     var i = 0, len = items.length, result = Array(len);
     while (i<len){
      result[i] = items[i];
      i++;
     }
     return result;
    }
    }
  • When Reflow?
    • 처음 페이지를 불러올 때
    • 브라우저 창 크기가 변경될 때
    • DOM 노드가 추가되거나 제거될 때 ex) list.appendChild(item)
    • 레이아웃 스타일이 적용될 때
      What to do?
      - style 속성 변경을 최소화하라
      - style 속성 대신 CSS class에 정의하고 className 속성을 변경하라
    • 레이아웃 정보를 검색할 때
      - Only if reflow is cached
      What to do?
      - 레이아웃 정보 접근을 최소화 하라
      - 한 번 이상 사용될 값은 지역 변수에 저장하라
  • DocumentFragment
    • 도큐먼트 같은 객체
    • 시각적으로 나타나지 않음
    • 그것이 만들어진 도큐먼트의 자식으로 간주
    • addChild()를 전달할 때 자신보다는 그것의 자식 모두를 추가
    var list = document.getElementById("list");
    var fragment = document.createDocumentFragment();
    
    for ( var i=0;i<10; i++ ){
    var item= document.createElement("li");
    fragment.appendChild(item); // No reflow! 새로 생성된 도큐먼트에 붙이므로...
    }
    
    list.appendChild(fragment); // Reflow! 현재 도큐먼트에 붙이므로...

당신의 DOM을 빠르게~!

  • HTMLCollection objects 사용을 주의하라
  • 도큐먼트에 DOM 조작 수행을 줄여라
  • CSS style 대신 CSS class를 사용하라
  • 레이아웃 정보에 접근할 때 주의하라

Browsers With Optimizing Engines

  • Chrome(V8)
  • Safari 4+ (Nitro)
  • Firefox 3.5+ (TraceMonkey)
  • Opera 10?11? (Carakan)
All use native code generation and JIT compiling to achieve faster JavaScript excution

Summary

  • 스코프에 주의하라
  • 지역 변수는 당신의 친구들이다
  • 함수 실행은 비용이 따른다
  • 반복은 조금만 유지하라
  • 가능하면 언제나 작업을 피하라
  • DOM 상호작용은 최소화하라
  • 좋은 브라우저를 사용하고 다른 이들에게도 장려하라

댓글 없음:

댓글 쓰기