Dom 노드를 최적화하는 방법

醉折花枝作酒筹
풀어 주다: 2021-04-12 11:16:39
원래의
2458명이 탐색했습니다.

이 글에서는 Dom 노드의 최적화 계획을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

Dom 노드를 최적화하는 방법

DOM 작업은 브라우저 다시 그리기 및 리플로우로 이어지기 때문에 성능에 가장 큰 영향을 미칩니다. DOM은 DOM 작업을 용이하게 하는 많은 API를 제공하지만, 그러나 DOM 작업은 매우 비용이 많이 들고 페이지의 프런트엔드 코드에서 발생하는 성능 병목 현상의 대부분은 DOM 작업에 집중되어 있습니다. 따라서 프런트엔드 성능 최적화의 주요 초점은 DOM 작업의 최적화입니다.

브라우저 렌더링 메커니즘:

Dom 노드를 최적화하는 방법
브라우저는 페이지를 렌더링합니다.
Dom 노드를 최적화하는 방법

  1. 브라우저는 HTML 문서의 소스 코드를 구문 분석한 다음 DOM 트리를 구성하고 스타일이 발견될 때 이를 비동기적으로 계산합니다.

  2. 비동기적으로 계산된 스타일은 DOM 트리와 합성되어 렌더 트리를 구축합니다.

  3. 렌더 트리를 레이아웃합니다.

  4. 렌더 트리 페인팅.

DOM 트리와 렌더 트리의 차이점은 display:none 스타일의 노드가 DOM 트리에는 있지만 렌더 트리에는 없다는 것입니다. 브라우저는 이를 그린 후 js 파일을 구문 분석하기 시작하고 js를 기반으로 다시 그리기 및 리플로우 여부를 결정합니다.

Reflow·Redraw

페이지가 변경될 때 발생하는 작업:

  1. Reflow: 브라우저 엔진은 렌더링 트리의 특정 노드가 변경되어 레이아웃에 영향을 미치고 돌아가서 다시 렌더링해야 함을 발견합니다. 이 롤백 프로세스를 reflow라고 부릅니다. 리플로우는 이 루트 프레임에서 아래쪽으로 반복되어 모든 노드의 기하학적 치수와 위치를 순서대로 계산합니다.
  2. Redraw: 페이지의 DOM 레이아웃에 영향을 주지 않고 요소의 배경색, 텍스트 색상, 테두리 색상 등을 변경합니다.

js는 단일 스레드입니다. 다시 그리기 및 리플로우는 사용자 작업을 차단하고 웹 페이지 성능에 영향을 미칩니다.

최적화: 리플로우 다시 그리기 수를 줄입니다. 1. 스타일 대신 클래스를 사용합니다. 리플로우 및 다시 그리기의 여러 트리거

예: DOM 요소의 너비와 높이를 변경합니다

var dom = document.getElementById('box')
dom.style.width = '300px'
dom.style.height = '300px'//访问了三次dom,触发了两次回流和两次重绘
로그인 후 복사

최적화 후:

.change {
    width: 300px;
    height: 300px;
    }
    document.getElementById('p').className = 'change'//只触发一次
로그인 후 복사

2 목록 유형을 일괄 수정하고 문서 흐름에서 벗어나 복원합니다. 스타일 display:none을 사용하면 DOM에는 있지만 렌더링 트리에는 없으므로 다시 그리기 리플로우가 발생하지 않습니다.


DOM 컬렉션의 각 DOM 하위 노드에 클래스를 추가하려는 경우 각 노드에 클래스를 순회하여 추가하면 여러 번 다시 그리기 및 리플로우가 실행됩니다.

/* //需要加入的样式
.change {
    width: 300px;
    height: 300px;
}
*/
var ul = document.getElementsByTagName('ul')
var lis = document.getElementsByTagName('li') 
ul.style.display = 'none'
for(var i = 0; i < lis.length; i++) {
    lis[i].className = &#39;change&#39;;
     }
     ul.style.display = &#39;block&#39;
로그인 후 복사

3 DocumentFragment


가상 DOM은 실제로 객체.js는 빈 가상 노드 객체를 생성하는 reateDocumentFragment() 메서드를 제공합니다. DocumentFragment 노드는 문서 트리에 속하지 않습니다. 이러한 요소를 DocumentFragment에 먼저 추가한 다음 DocumentFragment 객체를 렌더링 트리에 추가하면 페이지에서 DOM을 렌더링하는 횟수가 줄어들고 효율성이 크게 향상됩니다.

var frag = document.createDocumentFragment() //创建一个虚拟节点对象	
for(var i = 0; i < 10; i++) {				
    var li = document.createElement("li")		
    li.innerHTML = &#39;我是第&#39; + i + 1 + &#39;个元素&#39;		
    frag.appendChild(li)  //将li元素加到虚拟节点对象上
    } 			
    ul.appendChild(frag)  //将虚拟节点对象加到ul上
로그인 후 복사

Others
1. 브라우저 이벤트와 버블링 캡처를 사용하여 페이지 이벤트 바인딩을 줄이는 이벤트 핸들러를 지정하여 특정 유형의 모든 이벤트를 관리할 수 있습니다. 이벤트 함수가 너무 많으면 많은 메모리를 차지하게 되고 이벤트에 바인딩된 DOM 요소가 많아질수록 DOM 방문 횟수가 늘어나고 페이지의 대화형 준비 시간도 지연됩니다.

// 事件委托前
var lis = document.getElementsByTagName(&#39;li&#39;)
for(var i = 0; i < lis.length; i++) {
   lis[i].onclick = function() {
      console.log(this.innerHTML)
   }}    // 利用浏览器事件通过父元素委托事件给子元素
   var ul = document.getElementsByTagName(&#39;ul&#39;)ul.onclick = function(event) {
	//也可以做判断给指定的子元素绑定事件
   console.log(event.target.innerHTML)};
로그인 후 복사

2. 루프 최적화로 DOM 작업 횟수가 줄어듭니다

//例子1:减少在计算过程中操作dom
// 优化前,访问了好多次dom,这些都是细节问题,有经验的绕过,小白平常多注意就行
for(var i = 0; i < 10; i++) {
    document.getElementById(&#39;el&#39;).innerHTML += &#39;1&#39;} 
    // 优化后 
    var str = &#39;&#39;for(var i = 0; i < 10; i++) {
    str += &#39;1&#39;}document.getElementById(&#39;el&#39;).innerHTML = str/
로그인 후 복사

이렇게 보면 캐시 노드 길이의 효과를 경험할 수 없습니다. 아래 예시를 참조하세요

//不缓存
var ps = document.getElementsByTagName("p"), i, p;
for( i=0; i<ps.length; i++ ){  
    p = document.createElement("p");
    document.body.appendChild("p");
    }造成死循环,每次执行for循环都会动态获取ps的长度,而我们每次进入循环都增加了一个DOM(p),ps的长度也+1.
    //缓存
    var ps = document.getElementsByTagName("p"), i, p,len;
    for( i=0;len=ps.length;i<len; i++ ){  
        p = document.createElement("p");
        document.body.appendChild("p");
    }//使用变量保存ps的长度。
로그인 후 복사

3.


요소 가져오기 가장 일반적인 두 가지 방법은 getElementsByXXX()와 queryselectorAll()입니다. 이 두 선택기의 차이점은 전자가 동적 컬렉션을 얻는 것이고 후자는 정적 컬렉션을 얻는 것입니다

// 假设一开始有2个livar 
lis = document.getElementsByTagName(&#39;li&#39;)  // 动态集合
var ul = document.getElementsByTagName(&#39;ul&#39;)[0]
 for(var i = 0; i < 3; i++) {
    console.log(lis.length)
    var newLi = document.createElement(&#39;li&#39;)
    ul.appendChild(newLi)}// 输出结果:2, 3, 4
    // 优化后
    var lis = document.querySelectorAll(&#39;li&#39;)  // 静态集合 
    var ul = document.getElementsByTagName(&#39;ul&#39;)[0]
 for(var i = 0; i < 3; i++) {
    console.log(lis.length)
    var newLi = document.createElement(&#39;li&#39;)
    ul.appendChild(newLi)}// 输出结果:2, 2, 2
로그인 후 복사

Operations 정적 컬렉션에서는 문서를 다시 쿼리하는 것이 동적 컬렉션보다 더 최적화되지 않습니다.


추천 학습:

javascript 비디오 튜토리얼

위 내용은 Dom 노드를 최적화하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:csdn.net
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!