Wir wissen, dass DOM eine Anwendungsprogrammierschnittstelle zum Betreiben von XML- und HTML-Dokumenten ist und es sehr teuer ist, Skripte zum Betreiben von DOM zu verwenden. Es gibt eine treffende Metapher: Stellen Sie sich vor, dass DOM und JavaScript (hier ECMScript) jeweils eine Insel sind und durch eine Mautbrücke verbunden sind. Jedes Mal, wenn ECMAScript auf das DOM zugreift, muss es diese Brücke passieren und eine „Brückengebühr“ zahlen. Je öfter Sie auf das DOM zugreifen, desto höher sind die Kosten. Daher besteht die empfohlene Vorgehensweise darin, so wenig Brücken wie möglich zu überqueren und zu versuchen, auf der ECMAScript-Insel zu bleiben. Es ist für uns unmöglich, die DOM-Schnittstelle nicht zu verwenden. Wie können wir also die Effizienz des Programms verbessern?
1. DOM-Zugriff und -Änderung
Der Zugriff auf DOM-Elemente ist kostspielig (Sie kennen die „Maut“), und das Ändern von Elementen ist noch kostspieliger, da der Browser dadurch die geometrischen Änderungen der Seite neu berechnen muss (Umfließen und Neuzeichnen).
Das schlimmste Szenario ist natürlich der Zugriff auf oder die Änderung von Elementen in einer Schleife. Sehen Sie sich die folgenden beiden Codeteile an:
var times = 15000; // 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);
Dadurch war die erste Laufzeit tausendmal länger als beim zweiten Mal! (Chromversion 44.0.2403.130 m)
1: 2846.700ms 2: 1.046ms
Das Problem mit dem ersten Codeteil besteht darin, dass bei jeder Schleifeniteration zweimal auf das Element zugegriffen wird: einmal, um den Wert von innerHTML zu lesen, und ein anderes Mal, um ihn neu zu schreiben, d. h. jedes Mal, wenn die Schleife die Brücke überquert ( re- Rudern und Neuzeichnen wird im nächsten Artikel erklärt)! Die Ergebnisse zeigen deutlich, dass der Code umso langsamer ausgeführt wird, je öfter auf das DOM zugegriffen wird. Daher wird die Anzahl der DOM-Zugriffe, die reduziert werden können, so weit wie möglich reduziert und die Verarbeitung so weit wie möglich der ECMAScript-Seite überlassen.
2. HTML-Sammlung und Durchqueren des DOM
Ein weiterer energieintensiver Punkt beim Betrieb von DOM ist das Durchlaufen von DOM. Im Allgemeinen sammeln wir eine Sammlung von HTML, z. B. mithilfe von getElementsByTagName () oder document.links usw. Ich denke, jeder ist damit vertraut. Das Ergebnis der Sammlung ist eine Array-ähnliche Sammlung, die in einem „Live-Status“ in Echtzeit vorliegt, was bedeutet, dass sie automatisch aktualisiert wird, wenn das zugrunde liegende Dokumentobjekt aktualisiert wird. Wie sagt man es? Es ist ganz einfach, eine Kastanie zu verschenken:
<body> <ul id='fruit'> <li> apple </li> <li> orange </li> <li> banana </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>
Und hier kommt die Ineffizienz her! Es ist sehr einfach, genau wie die Optimierungsoperation des Arrays, das Zwischenspeichern der Längenvariablen ist in Ordnung (das Lesen der Länge einer Sammlung ist viel langsamer als das Lesen der Länge eines gewöhnlichen Arrays, da es jedes Mal abgefragt werden muss):
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);
Mal sehen, wie viel Leistungsverbesserung erreicht werden kann?
0: 0.974ms 1: 0.664ms
Wenn die Sammlung groß ist (die Demo beträgt 1000), ist die Leistungsverbesserung immer noch offensichtlich.
„Hochleistungs-JavaScript“ schlägt eine weitere Optimierungsstrategie vor, die besagt: „Da das Durchlaufen eines Arrays schneller ist als das Durchlaufen einer Sammlung, ist der Zugriff auf seine Eigenschaften schneller, wenn Sie zuerst die Sammlungselemente in das Array kopieren.“ hat dieses Muster nicht sehr gut offenbart, also kümmern Sie sich nicht darum. Der Testcode lautet wie folgt: (Wenn Sie Fragen haben, können Sie diese gerne mit mir besprechen)
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);
Am Ende dieses Abschnitts stellen wir zwei native DOM-Methoden vor: querySelector() und querySelectorAll(). Erstere gibt ein Array zurück (beachten Sie, dass sich ihre Rückgabewerte nicht dynamisch ändern). wie HTML-Sammlungen), und letzteres gibt das erste übereinstimmende Element zurück. Nun, es ist nicht immer besser als die HTML-Sammlungsdurchquerung des ersteren.
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
Da es sich jedoch um eine CSS-ähnliche Auswahlmethode handelt, ist sie bei der Kombinationsauswahl effizienter und bequemer. Führen Sie beispielsweise die folgende kombinierte Abfrage aus:
var elements = document.querySelectorAll('#menu a'); var elements = document.querySelectorAll('div.warning, div.notice');
Das Obige dreht sich alles um die leistungsstarke JavaScript-DOM-Programmierung. Ich hoffe, Sie können es verstehen und es wird Ihnen beim Lernen helfen.