웹 프론트엔드 개발에 숨겨진 성능 비용 - Reflow & Repaint 발표자. 엄 두성
웹 프론트엔드 개발에 숨겨진 성능 비용
- Reflow & Repaint
발표자. 엄 두성
브라우저 렌더링 프로세스의 이해
• Rendering Engine Basic Flow :
브라우저가네트워크계층에서 요청된데이터를 받아오면
렌더링 엔진이 움직이기시작한다.
HTML Code
DOM Tree
documentElement(html)
head body
meta title style p div
CSS Code
Styles Structure
StylingInformation
cascades
Parse Parse
: 랜더링엔진에서코드를파싱하여 DOM Tree를생성
Render Tree
root(render view)
body
DOM TreeStyles
Structure
p
: DOM을화면에그리기위한정보들을 Rendering Tree로생성
Render Tree
root(render view)
body
p
: 생성된 Rendering Tree로 Element의위치나크기정보를생성
http://www.youtube.com/watch?v=nJtBUHyNBxs
http://www.youtube.com/watch?v=AKZ2fj8155I
: 생성된정보를바탕으로실제화면을그린다.
브라우저 렌더링 프로세스의 이해
Reflow Repaint
그렇다면..
화면구성이완료된 후 동적인 변화발생시엔?
• 특정엘리먼트의 Color 값에변화 발생
→ 해당엘리먼트의 Repaint 발생
• 엘리먼트의포지션에변화가발생
→ 해당엘리먼트의 Repaint + 레이아웃의 Reflow 발생
즉, 엘리먼트의폰트 사이즈를키우는단순한작업만추가 되더라도
전체 Render Tree의 Repaint와 Reflow를 유발
Reflow? Repaint?
• Repaint (or Redraw) :
1. 엘리먼트의 스킨에 변화가 발생하지만,
레이아웃에는 영향을 미치지 않을 때 유발
• Reflow :
1. 문서 내 노드들의레이아웃, 포지션을 재계산 후 다시 뿌림
2. Repaint 보다도 더 심각한 퍼포먼스 저하를 유발시키는 프로세스
무엇이 Reflow를 유발시키는가?
- 브라우저창 크기 수정
- DOM 트리 수정
- Style sheet 추가
- Style Property 수정
- 편집 ( 입력, ContentEditable )
- 등등..
Reflow 발생 example
Reflow 발생 그래프 :
단계별설명1.Click 이벤트2.Recalculate ( 변경된스타일수치 계산수행)3.Layout (Reflow 과정 수행)4.Paint (Repaint 과정 수행)
function reflow() {document.getElementById(‘container’).style.width=600px;
}
Reflow를 피하거나 그 영향을 최소화하는 방법
1. 애니메이션이들어간 노드는 position:fixed 또는
position:absolute로지정하여전체 노드에서분리
2. cssText 를 활용해 Reflow or Repaint 최소화
3. DOM 사용을 최소화하여 Reflow 비용 줄이기
4. 등등..
특정 노드의 Position 속성 변경 (1)
- position 속성을 "fixed" 또는 "absoute"로 값을 주면
해당 노드는 전체 노드에서 분리 됨.
즉, 전체 노드에걸쳐 Reflow 비용이들지 않으며,
해당 노드의 Repaint 비용만 들어가게됨.
특정 노드의 Position 속성 변경 (1)
테스트 코드:
<div id="container_animation“
style="background:blue;
position:absolute;
top:0px;left:0px;width:100px;height:100px;
border:red 1px solid;">
</div>
function animation() {document.getElementById('container_animation').style.left = '100px';document.getElementById('container_animation').style.top = '100px';return false;
}
특정 노드의 Position 속성 변경 (2)
테스트 결과:
cssText 를 활용해 Reflow 최소화 (1)
- DOM과 스타일 변경을하나로 묶어 Reflow 수행을
최소화 한다.
cssText 를 활용해 Reflow 최소화 (2)
case 1 : (Bad Case) 해당노드의 style 객체를여러번호출해적용
function collect() {var elem = document.getElementById('container');
elem.style.backgroundColor = 'red';elem.style.width = '200px';elem.style.height = '200px';
return false;}
cssText 를 활용해 Reflow 최소화 (3)
case 2 : style 객체 속성인 cssText를통해한번에적용.
function collect() {var elem = document.getElementById('container');
elem.style.cssText = 'background:red;width:200px;height:200px;';
return false;}
cssText 를 활용해 Reflow 최소화 (4)
테스트결과 :
상황별 Reflow 비용에드는시간.
Case 1 : 112ms
Case 2 : 104ms
DOM 사용을 최소화하여 Reflow 비용 줄이기(1)
- 노드 조각(document.createDocumentFragment),
노드 사본(elem.cloneNode) 을 활용하여 DOM 접근을
최소화 하여 비용을줄일 수 있다.
DOM 사용을 최소화하여 Reflow 비용 줄이기(2)
Case 1 : (Bad Case)
function notReflow() {
var elem = document.getElementById('container');
for (var i = 0; i < 10; i++) {var a = document.createElement('a');a.href = '#';a.appendChild(document.createTextNode('test' + i));elem.appendChild(a);
}
return false;}
DOM 사용을 최소화하여 Reflow 비용 줄이기(3)
Case 2 : 노드 조각을 활용한 엘리먼트 추가 방법
function notReflow() {
var frag = document.createDocumentFragment();
for (var i = 0; i < 10; i++) {var a = document.createElement('a');a.href = '#';a.appendChild(document.createTextNode('test' + i));frag.appendChild(a);
}
document.getElementById('container').appendChild(frag);
return false;}
DOM 사용을 최소화하여 Reflow 비용 줄이기(4)
Case 3 : 노드 사본을 활용한 엘리먼트 추가 방법
function notReflow() {
var elem = document.getElementById('container');var clone = elem.cloneNode(true);
for (var i = 0; i < 10; i++) {var a = document.createElement('a');a.href = '#';a.appendChild(document.createTextNode('test' + i));clone.appendChild(a);
}
elem.appendChild(clone);
return false;}
DOM 사용을 최소화하여 Reflow 비용 줄이기(5)
상황별 테스트 결과:
Case 1 : 153ms
Case 2 : 136ms
Case 3 : 129ms
Thank you