>  기사  >  웹 프론트엔드  >  JavaScript에 최적화된 DOM

JavaScript에 최적화된 DOM

php中世界最好的语言
php中世界最好的语言원래의
2018-03-19 16:27:091870검색

이번에는 DOM 최적화를 위한 JavaScript와 DOM 최적화를 위한 JavaScript용 notes에 대해 소개하겠습니다.

DOM 최적화는 오래전부터 다시 그리기 및 리플로우로 시작해야 합니다...

1. 다시 그리기 및 리플로우

1.1 다시 그리기 및 리플로우란

다시 그리기는 일부 스타일 수정을 의미하지만, 요소의 위치와 크기가 변경되지 않았습니다.

재배열은 요소의 위치나 크기가 변경되었음을 의미하며 브라우저는 새 렌더링 트리가 설정된 후 영향을 받는 요소를 다시 계산해야 합니다. 다시 그려집니다.

1.2 브라우저 렌더링 페이지

인터뷰에 가면 항상 묻는 질문이 있습니다. 즉, "브라우저에 URL 한 줄을 입력하면 어떻게 되나요?" 이 질문에 대한 대답에는 추가 사항이 필요합니다. 네트워크 지식에 대한 브라우저 렌더링 페이지 문제도 포함됩니다. 브라우저가 서버로부터 응답된 페이지를 받으면 한 줄씩 렌더링을 시작합니다. CSS를 만나면 속성 값을 비동기적으로 계산한 다음 구문 분석이 완료된 후 DOM 트리를 계속해서 구문 분석합니다. 계산된 스타일(스타일 상자)은 DOM 트리와 결합되어 렌더 트리를 형성하고, 브라우저가 이를 페이지에 그립니다. DOM 트리와 렌더 트리의 차이점은 display:none 스타일의 노드가 DOM 트리에는 있지만 렌더 트리에는 없다는 것입니다. 그리기를 마친 후 브라우저는 js 파일을 구문 분석하기 시작하고 js를 기반으로 다시 그리기 및 리플로우 여부를 결정합니다.

1.3 다시 그리기 및 리플로우를 수행하는 이유

다시 그리기를 유발하는 요소:

리플로우를 유발하는 요인:

간단히 말해서 js는 단일 스레드이고 다시 그리기 및 리플로우는 사용자 작업을 차단하고 영향을 미친다는 것을 알아야 합니다. 예를 들어 페이지 요소의 너비와 높이를 500ms마다 변경하는 타이머를 작성하는 경우와 같이 페이지가 여러 번 다시 그려지고 리플로우되면 페이지가 점점 더 중단될 수 있습니다. 최대한 리플로우합니다. 그런 다음 DOM 최적화도 이 시작점을 기반으로 합니다.

2. 최적화

2.1 액세스 감소

당연히 요소 캐싱을 의미하지만

var ele = document.getElementById('ele');

이는 ele에 대한 각 호출은 여전히 ​​ID에 한 번 액세스하는 것과 동일합니다. .은 ele의 노드입니다.

2.1.1 Cache NodeList

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의 길이를 가져오다가 요소를 추가하는 등 무한 루프가 발생할 수 있습니다.

2.1.2 선택기 변경

요소를 얻는 가장 일반적인 두 가지 방법은 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

정적 컬렉션에 대한 작업으로 인해 문서가 다시 쿼리되지 않으므로 동적 컬렉션보다 더 최적화됩니다.

2.1.3 불필요한 루프 방지

// 优化前
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번 액세스하는 반면, 최적화된 코드는 한 번만 액세스하므로 효율성이 크게 향상됩니다.

2.1.4 이벤트 위임

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에 한 번만 방문했습니다.

2.2 다시 그리기 및 재배열 줄이기

2.2.1 dom 노드의 여러 스타일 변경

p 요소의 너비와 높이를 변경하고 싶습니다. 일반적인 접근 방식은 다음과 같습니다

 p = document.getElementById('p1'

The 위의 작업 요소의 두 가지 속성이 변경되었고 DOM에 세 번 액세스했으며 두 번의 재배열과 두 번의 다시 그리기가 트리거되었습니다. 최적화는 방문 횟수와 다시 그리기 및 재정렬 횟수를 줄이는 것이라고 말했습니다. 이 시작점에서 요소에 한 번만 액세스하고 재정렬 횟수를 1로 줄일 수 있습니까? 분명히 가능합니다. CSS로 클래스를 작성할 수 있습니다

/* css
.change {
    width: 220px;
    height: 300px;
}*/document.getElementById('p').className = 'change';

이 방법으로 한 번에 여러 스타일을 조작할 수 있습니다

2.2.2 DOM 노드 스타일을 일괄 수정합니다

위 코드는 하나의 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';

3、总结

  • 减少访问dom的次数

    • 缓存节点属性值

    • 选择器的使用

    • 避免不必要的循环

    • 事件委托

  • 减少重绘与重排

    • 使用className改变多个样式

    • 使父元素脱离文档流再恢复

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

Vue的计算属性

Webpack模块的使用

위 내용은 JavaScript에 최적화된 DOM의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.