ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바스크립트 성능이야기(리플로&리페인트)
    My-Book(History) 2015. 3. 28. 10:45

    ★- 리플로 와 리페인트


    리플로 : 

    변경(일부 또는 전체)이 필요한 렌더 트리에 대한 유효성 확인 작업과 함께 노드의 크기와 위치를 다시 계산한다. 이과정을 리폴로 또는 레이아웃, 레이아웃팅 이라 부른다.

    노드의 '크기' 또는 '위치'가 바뀌어 현재 레이아웃에 영향을 미쳐 배치를 다시 해야 할 때 리플로가 발생한다.


    리페인트 :

    변경 영역의 결과를 표현하기 위해 화면이 업데이트되는 것을 의미한다. 리플로가 발생 하거나 배경색 변경 등의 단순한 스타일 변경과 같은 작업이 발생하는 경우다.




    ★- 리플로 최소화 방법


    작업 그루핑

    잘못된 예 :

    function change() {

    var width = document.getElementById("layer1").style.width;

    document.getElementById("layer2").style.width = width;

    var height = document.getElementById("layer3").style.height;

    document.getElementById("layer4").style.height = height;

    }

    이 코드를 실행하면 리플로가 여러 번 발생할 수 있다. 따라서 다음과 같이 비슷한 형태의 작업끼리 그룹으로 묶어 실행되도록 순서를 변경하면 렌더링 처리를 향상 시킬 수 있다.


    function change() {

    var width = document.getElementById("layer1").style.width;

    var height = document.getElementById("layer3").style.height;

    document.getElementById("layer2").style.width = width;

    document.getElementById("layer4").style.height = height;

    }

    캐싱

    별도의 변수에 자주 사용하는 값을 저장하는것을 의미한다.

    자주 사용하는 속성의 값이나 메서드의 반환값을 변수에 저장하면 직접 속성이나 메서드를 호출하는 

    횟수를 줄여 성능을 향상시킬 수 있다.

    잘못된 예 :


    for() {

    el.,style.width = el.scrollWidth + "px";

    el.style.left = el.scrollLeft + "px" ;

    }

    이 경우 값을 최대한 별도의 변수에 캐싱해 자주 호출되지 앟게 하면 리플로의 발생 빈도를 낮출 수 있다.

    var nWidth = el.scrollWidth, nLeft = el.scrollLeft;

    for() {

    el.style.width = nWidth + "px" ;

    el.style.left = nLeft + "px";

    }



    ===========================================================================



    스타일 변경은 한 번에 몰아서 처리하라

    브라우저가 렌더링 되는 과정을 간단하게 설명하면 아래와 같다.

    Step1          HTML과 CSS를 파싱하여 DOM Tree와 Style 문맥을 생성한다.
    Step2          DOM Tree와 Style 문맥을 기반으로 엘리먼트의 색상, 면적 등의 정보를 가진 Render Tree를 생성한다.
    Step3          Render Tree를 기반으로 각 노드가 화면의 정확한 비치에 표시되도록 배치한다.
    Step4          배치된 노드들의 visibility, outline, color 등의 정보를 시각적으로 표현한다.
    

    Step3의 과정을 Reflow, Step4의 과정을 Repaint라고 한다. 자바스크립트에서 DOM을 조작하면 브라우저 내부적으로 Reflow와 Repaint가 반복적으로 수행되는데, 이 두 과정이 서비스 성능 비용의 대부분을 차지한다. 결과적으로 이 두 과정에서 발생되는 비용을 얼마나 절감할 수 있는냐가 서비스의 성능을 결정한다고 해도 과언이 아니다.

    Solution: 
    Reflow와 Repaint가 최소한으로 발생하도록 몰아서 처리한다.

    [Bad]

    <div id="container">
        <div id="sample" style="position:absolute;background:red; width:150px;height:50px">
            Sample BOX
        </div>
    </div>
    function changeDivStyle(){
        var sampleEl = document.getElementById('sample');
        sampleEl.style.left = '200px';               // reflow 1회, repaint 1회 발생
        sampleEl.style.width = '200px';              // reflow 1회, repaint 1회 발생
        sampleEl.style.backgroundColor = 'blue';     // repaint 1회 발생
    }
    
    // 총 reflow 2회, repaint 3회 발생
    changeDivStyle();

    [Good]

    <div id="container">
        <div id="sample" style="position:absolute;background:red; width:150px;height:50px">
            Sample BOX
        </div>
    </div>
    // cloneNode를 사용하는 방법
    function changeDivStyle(){
        var sampleEl = document.getElementById('sample'),
            clone = sampleEl.cloneNode(true);
        clone.style.left = '200px';
        clone.style.width = '200px';
        clone.style.backgroundColor = 'blue';
        document.getElementById("container").replaceChild(clone, sampleEl);    // reflow 1회, repaint 1회 발생
    }
    changeDivStyle();
    // cssText를 사용하는 방법
    function changeDivStyle(){
        var sampleEl = document.getElementById('sample');
        sampleEl.style.cssText = 'position:absolute;background:blue; width:200px;height:50p;left:200px;';    // reflow 1회, repaint 1회 발생
    }
    changeDivStyle();

    참고
    위의 코드는 이해를 돕기 위한 예시일 뿐, 실제 개발에서는 스크립트 코드 내에서 CSS를 직접 수정하지 말고, className을 수정하는 방법을 사용해야 한다.

    출처 : https://github.com/nhnent/fe.javascript/wiki/%EC%95%88%ED%8B%B0-%ED%8C%A8%ED%84%B4

Designed by Tistory.