高性能JavaScriptのDOMプログラミング


DOMはXMLとHTMLドキュメントを操作するためのアプリケーションインターフェースであり、シナリオでDOM操作すると高価であることを知っています.適切な比喩があります.DOMとJavaScriptはそれぞれ一つの島を想像しています.その間は有料の橋で接続しています.ECMAScriptは毎回DOMを訪問します.この橋を経由して、そして「橋を渡る費用」を納めて、DOMを訪問する回数が多いほど、費用も高くなります.そのため、橋を渡る回数をできるだけ減らして、ECMAScript島にいるようにするのがオススメです.DOMインターフェースを使わないわけにはいかないですが、どうやってプログラムの効率を上げることができますか?
1、DOMアクセスと修正
DOM元素にアクセスすると、より高価な要素の修正ができます.これはブラウザがページの幾何学的変化を再計算することにつながるからです.もちろん最悪の場合はループ中に要素にアクセスしたり、修正したりします.次の二つのコードを見てください.
var times = 200;

// code1
console.time(1);
for(var i = 0; i < times; i++) {
 document.getElementById('myDiv1').innerHTML += 'a';
}
console.timeEnd(1);

// code2
console.time(2);
var str = '';
for(var i = 0; i < times; i++) {
 str += 'a';
}
document.getElementById('myDiv2').innerHTML = str;
console.timeEnd(2);
その結果、初めての運行時間はなんと2回目の数十倍!(chromeバージョン44.0.2403.130 m)
1: 5.538ms
2: 0.111ms
第一段コードの問題は、繰り返しのたびに、この要素は二回訪問されることです.一回はinnerHTMLの値を読み取り、もう一回はそれを書き直します.つまり、毎回循環して橋を渡っています.その結果,DOMへのアクセスが多くなり,コードの動作速度が遅くなることが十分に示された.したがって、DOM訪問の回数を減らすことができるなら、できるだけECMAScriptに残して処理します.
2、HTML集合&エルゴードDOM
DOMを操作するもう一つの消耗点はDOMを遍歴することです.一般的に私達はHTMLの集合を収集します.例えばgetElements ByTagName()を使ったり、document.linksを使ったりします.みんなはこれに慣れていないと思います.収集の結果は、同じ配列の集合であり、「リアルタイム状態」でリアルタイムに存在しています.これは、下の文書オブジェクトが更新されると自動的に更新されることを意味します.どう言いますか?簡単に栗を挙げます.
<body>
 <ul id='fruit'>
 <li> apple </li>
 <li> orange </li>
 <li> banana </li>
 <li> stabery </li>
 </ul>
</body>
<script type="text/javascript"> var lis = document.getElementsByTagName('li'); var peach = document.createElement('li'); peach.innerHTML = 'peach'; document.getElementById('fruit').appendChild(peach); console.log(lis.length); // 4 </script>
これはまさに非効率の源です!簡単です.配列の最適化操作と同じで、length変数をキャッシュするとokです.
console.time(0);
var lis0 = document.getElementsByTagName('li');
var str0 = '';
for(var i = 0; i < lis0.length; i++) {
 str0 += lis0[i].innerHTML;
}
console.timeEnd(0);


console.time(1);
var lis1 = document.getElementsByTagName('li');
var str1 = '';
for(var i = 0, len = lis1.length; i < len; i++) {
 str1 += lis1[i].innerHTML;
}
console.timeEnd(1);
性能の向上はどれぐらいありますか?
0: 0.974ms
1: 0.664ms
集合の長さが大きい場合(デモは1000)、性能の向上は明らかである.「高性能JavaScript」は、もう一つの最適化戦略を提示しました.「行列を遍歴するのは集合より速いので、まず集合要素を配列にコピーすると、その属性にアクセスするのがより速い」と指摘しました.(疑義がありますので、私と交流して検討してください)
console.time(1);
var lis1 = document.getElementsByTagName('li');
var str1 = '';
for(var i = 0, len = lis1.length; i < len; i++) {
 str1 += lis1[i].innerHTML;
}
console.timeEnd(1);


console.time(2);
var lis2 = document.getElementsByTagName('li');
var a = [];
for(var i = 0, len = lis2.length; i < len; i++)
 a[i] = lis2[i];

var str2 = '';
for(var i = 0, len = a.length; i < len; i++) {
 str2 += a[i].innerHTML;
}
console.timeEnd(2);
その後改めて考えてみました.
console.time(2);
var lis2 = document.getElementsByTagName('li');
var a = [];
for(var i = 0, len = lis2.length; i < len; i++)
 a[i] = lis2[i];
 str2 += a[i].innerHTML;
console.timeEnd(2);
これは確かに大きな違いがあります.
1: 2.615ms
2: 0.164ms
3、querySelector()とquerySelectorAll()
今回の最後に2つの原生DOM方法を紹介します.querySelector()とquerySelectorAll()はみんながよく知らないと信じています.前者は一つの配列に戻ります.後者はマッチの最初の要素に戻ります.いいですよね.すべての場合、その性能は前者のHTML集合より優れています.
console.time(1);
var lis1 = document.getElementsByTagName('li');
console.timeEnd(1);

console.time(2);
var lis2 = document.querySelectorAll('li');
console.timeEnd(2);

// 1: 0.038ms
// 2: 3.957ms
しかし、CSSのような選択方法なので、グループ選択をする時には効率が上がり、便利です.たとえば、次のようなグループクエリを行います.
var elements = document.querySelectorAll('#menu a');
var elements = document.querySelectorAll('div.warning, div.notice');
以上、高性能JavaScript DOMプログラミングのすべての内容について、理解していただきたいと思います.