이 글에서는 Dom 노드의 최적화 계획을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.
DOM 작업은 브라우저 다시 그리기 및 리플로우로 이어지기 때문에 성능에 가장 큰 영향을 미칩니다. DOM은 DOM 작업을 용이하게 하는 많은 API를 제공하지만, 그러나 DOM 작업은 매우 비용이 많이 들고 페이지의 프런트엔드 코드에서 발생하는 성능 병목 현상의 대부분은 DOM 작업에 집중되어 있습니다. 따라서 프런트엔드 성능 최적화의 주요 초점은 DOM 작업의 최적화입니다.
브라우저 렌더링 메커니즘:
브라우저는 페이지를 렌더링합니다.
브라우저는 HTML 문서의 소스 코드를 구문 분석한 다음 DOM 트리를 구성하고 스타일이 발견될 때 이를 비동기적으로 계산합니다.
비동기적으로 계산된 스타일은 DOM 트리와 합성되어 렌더 트리를 구축합니다.
렌더 트리를 레이아웃합니다.
렌더 트리 페인팅.
DOM 트리와 렌더 트리의 차이점은 display:none 스타일의 노드가 DOM 트리에는 있지만 렌더 트리에는 없다는 것입니다. 브라우저는 이를 그린 후 js 파일을 구문 분석하기 시작하고 js를 기반으로 다시 그리기 및 리플로우 여부를 결정합니다.
페이지가 변경될 때 발생하는 작업:
js는 단일 스레드입니다. 다시 그리기 및 리플로우는 사용자 작업을 차단하고 웹 페이지 성능에 영향을 미칩니다.
var dom = document.getElementById('box') dom.style.width = '300px' dom.style.height = '300px'//访问了三次dom,触发了两次回流和两次重绘
.change { width: 300px; height: 300px; } document.getElementById('p').className = 'change'//只触发一次
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 = 'change'; } ul.style.display = 'block'
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 = '我是第' + i + 1 + '个元素' frag.appendChild(li) //将li元素加到虚拟节点对象上 } ul.appendChild(frag) //将虚拟节点对象加到ul上
Others
1. 브라우저 이벤트와 버블링 캡처를 사용하여 페이지 이벤트 바인딩을 줄이는 이벤트 핸들러를 지정하여 특정 유형의 모든 이벤트를 관리할 수 있습니다. 이벤트 함수가 너무 많으면 많은 메모리를 차지하게 되고 이벤트에 바인딩된 DOM 요소가 많아질수록 DOM 방문 횟수가 늘어나고 페이지의 대화형 준비 시간도 지연됩니다.
// 事件委托前 var lis = document.getElementsByTagName('li') for(var i = 0; i < lis.length; i++) { lis[i].onclick = function() { console.log(this.innerHTML) }} // 利用浏览器事件通过父元素委托事件给子元素 var ul = document.getElementsByTagName('ul')ul.onclick = function(event) { //也可以做判断给指定的子元素绑定事件 console.log(event.target.innerHTML)};
2. 루프 최적화로 DOM 작업 횟수가 줄어듭니다
//例子1:减少在计算过程中操作dom // 优化前,访问了好多次dom,这些都是细节问题,有经验的绕过,小白平常多注意就行 for(var i = 0; i < 10; i++) { document.getElementById('el').innerHTML += '1'} // 优化后 var str = ''for(var i = 0; i < 10; i++) { str += '1'}document.getElementById('el').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的长度。
요소 가져오기 가장 일반적인 두 가지 방법은 getElementsByXXX()와 queryselectorAll()입니다. 이 두 선택기의 차이점은 전자가 동적 컬렉션을 얻는 것이고 후자는 정적 컬렉션을 얻는 것입니다
// 假设一开始有2个livar lis = document.getElementsByTagName('li') // 动态集合 var ul = document.getElementsByTagName('ul')[0] for(var i = 0; i < 3; i++) { console.log(lis.length) var newLi = document.createElement('li') ul.appendChild(newLi)}// 输出结果:2, 3, 4 // 优化后 var lis = document.querySelectorAll('li') // 静态集合 var ul = document.getElementsByTagName('ul')[0] for(var i = 0; i < 3; i++) { console.log(lis.length) var newLi = document.createElement('li') ul.appendChild(newLi)}// 输出结果:2, 2, 2
Operations 정적 컬렉션에서는 문서를 다시 쿼리하는 것이 동적 컬렉션보다 더 최적화되지 않습니다.
추천 학습:
위 내용은 Dom 노드를 최적화하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!