이번에는 DOM 최적화를 위한 JavaScript와 DOM 최적화를 위한 JavaScript용 notes에 대해 소개하겠습니다.
DOM 최적화는 오래전부터 다시 그리기 및 리플로우로 시작해야 합니다...
다시 그리기는 일부 스타일 수정을 의미하지만, 요소의 위치와 크기가 변경되지 않았습니다.
재배열은 요소의 위치나 크기가 변경되었음을 의미하며 브라우저는 새 렌더링 트리가 설정된 후 영향을 받는 요소를 다시 계산해야 합니다. 다시 그려집니다.
인터뷰에 가면 항상 묻는 질문이 있습니다. 즉, "브라우저에 URL 한 줄을 입력하면 어떻게 되나요?" 이 질문에 대한 대답에는 추가 사항이 필요합니다. 네트워크 지식에 대한 브라우저 렌더링 페이지 문제도 포함됩니다. 브라우저가 서버로부터 응답된 페이지를 받으면 한 줄씩 렌더링을 시작합니다. CSS를 만나면 속성 값을 비동기적으로 계산한 다음 구문 분석이 완료된 후 DOM 트리를 계속해서 구문 분석합니다. 계산된 스타일(스타일 상자)은 DOM 트리와 결합되어 렌더 트리를 형성하고, 브라우저가 이를 페이지에 그립니다. DOM 트리와 렌더 트리의 차이점은 display:none 스타일의 노드가 DOM 트리에는 있지만 렌더 트리에는 없다는 것입니다. 그리기를 마친 후 브라우저는 js 파일을 구문 분석하기 시작하고 js를 기반으로 다시 그리기 및 리플로우 여부를 결정합니다.
다시 그리기를 유발하는 요소:
요소 크기, 위치 등을 변경하지 않고 가시성, 윤곽선, 배경색 및 기타 스타일 속성을 변경합니다. . 브라우저는 요소의 새 속성을 기반으로 다시 그립니다.
리플로우를 유발하는 요인:
. offsetTop
、offsetLeft
、 offsetWidth
、offsetHeight
、scrollTop
、scrollLeft
、scrollWidth
、scrollHeight
、 clientTop
、clientLeft
、clientWidth
、clientHeight
、getComputedStyle()
브라우저 창 크기 변경
창 크기 변경은 전체 웹 페이지 내 요소 크기 변경, 즉 DOM 요소의 컬렉션 속성 변경에 영향을 미치므로 재배열이 발생합니다.
스크롤 막대의 모양(전체 페이지의 리플로우를 트리거함)
간단히 말해서 js는 단일 스레드이고 다시 그리기 및 리플로우는 사용자 작업을 차단하고 영향을 미친다는 것을 알아야 합니다. 예를 들어 페이지 요소의 너비와 높이를 500ms마다 변경하는 타이머를 작성하는 경우와 같이 페이지가 여러 번 다시 그려지고 리플로우되면 페이지가 점점 더 중단될 수 있습니다. 최대한 리플로우합니다. 그런 다음 DOM 최적화도 이 시작점을 기반으로 합니다.
당연히 요소 캐싱을 의미하지만
var ele = document.getElementById('ele');
이는 ele에 대한 각 호출은 여전히 ID에 한 번 액세스하는 것과 동일합니다. .은 ele의 노드입니다.
var foods = document.getElementsByClassName('food');
food[i]를 사용하여 클래스 food로 i번째 요소에 접근할 수 있지만 여기의 음식은 배열이 아니라 NodeList입니다. NodeList는 정렬된 노드를 저장하고 위치별로 이러한 노드에 액세스할 수 있는 배열과 유사한 배열입니다. NodeList 개체는 동적이며 문서 기반 쿼리는 액세스할 때마다 실행됩니다. 따라서 NodeList에 대한 방문 횟수를 최소화해야 하며 NodeList의 값을 캐싱하는 것을 고려할 수 있습니다.
// 优化前var lis = document.getElementsByTagName('li');for(var i = 0; i < lis.length; i++) { // do something... }// 优化后,将length的值缓存起来就不会每次都去查询length的值var lis = document.getElementsByTagName('li');for(var i = 0, len = lis.length; i < len; i++) { // do something... }
그리고 NodeList는 동적으로 변경되기 때문에 캐시하지 않으면 NodeList의 길이를 가져오다가 요소를 추가하는 등 무한 루프가 발생할 수 있습니다.
요소를 얻는 가장 일반적인 두 가지 방법은 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, 4var lis = document.querySelector('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
정적 컬렉션에 대한 작업으로 인해 문서가 다시 쿼리되지 않으므로 동적 컬렉션보다 더 최적화됩니다.
// 优化前 for(var i = 0; i < 10; i++) { document.getElementById('ele').innerHTML += 'a';
} // 优化后 var str = ''; for(var i = 0; i < 10; i++) { str += 'a'; } document.getElementById('ele').innerHTML = str;
사전 최적화된 코드는 ele 요소에 10번 액세스하는 반면, 최적화된 코드는 한 번만 액세스하므로 효율성이 크게 향상됩니다.
js의 이벤트 함수는 모두 객체입니다. 이벤트 함수가 너무 많으면 많은 메모리를 차지하게 됩니다. 게다가 이벤트에 바인딩된 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')[0]; ul.onclick = function(event) { console.log(event.target.innerHTML); };
이벤트 위임 전에는 lis.length번의 li를 방문했지만, 이벤트 위임을 사용한 후에는 ul에 한 번만 방문했습니다.
p 요소의 너비와 높이를 변경하고 싶습니다. 일반적인 접근 방식은 다음과 같습니다
p = document.getElementById('p1'
The 위의 작업 요소의 두 가지 속성이 변경되었고 DOM에 세 번 액세스했으며 두 번의 재배열과 두 번의 다시 그리기가 트리거되었습니다. 최적화는 방문 횟수와 다시 그리기 및 재정렬 횟수를 줄이는 것이라고 말했습니다. 이 시작점에서 요소에 한 번만 액세스하고 재정렬 횟수를 1로 줄일 수 있습니까? 분명히 가능합니다. CSS로 클래스를 작성할 수 있습니다
/* css .change { width: 220px; height: 300px; }*/document.getElementById('p').className = 'change';
이 방법으로 한 번에 여러 스타일을 조작할 수 있습니다
위 코드는 하나의 dom 노드에 대한 것입니다. DOM 컬렉션의 스타일을 변경하고 싶다면?
가장 먼저 생각나는 방법은 컬렉션을 탐색하고 각 노드에 className을 추가하는 것입니다. 다시 생각해 보세요. 이는 dom 노드를 여러 번 방문했다는 의미가 아닌가요? 기사 시작 부분에서 언급한 DOM 트리와 렌더링 트리의 차이점을 생각해 보세요. 노드의 표시 속성이 없음이면 이 노드는 렌더 트리에 존재하지 않습니다. 즉, 이 노드의 작업은 렌더링 트리에 영향을 주지 않으며 다시 그리기 및 재배열이 발생하지 않습니다. 이 아이디어를 기반으로 최적화를 달성할 수 있습니다.
Display: none;
수정할 컬렉션의 상위 요소之后遍历修改集合节点
将集合父元素display: block;
// 假设增加的class为.changevar lis = document.getElementsByTagName('li'); var ul = document.getElementsByTagName('ul')[0]; ul.style.display = 'none';for(var i = 0; i < lis.length; i++) { lis[i].className = 'change'; } ul.style.display = 'block';
减少访问dom的次数
缓存节点属性值
选择器的使用
避免不必要的循环
事件委托
减少重绘与重排
使用className改变多个样式
使父元素脱离文档流再恢复
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 JavaScript에 최적화된 DOM의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!