Dieser Artikel bietet Ihnen eine Einführung in die Methoden der JavaScript-Leistungsoptimierung (mit Beispielen). Ich hoffe, dass er Ihnen weiterhilft.
Dieser Artikel basiert hauptsächlich auf der Lektüre von „Hochleistungs-Javascript“. Ich möchte einige nützliche Optimierungslösungen aufzeichnen und einige meiner eigenen Erfahrungen mit allen teilen.
Laden und Ausführen von Javascript
Wie wir alle wissen, blockiert der Browser beim Parsen des Skript-Tags alle anderen Aufgaben, bis die js-Datei heruntergeladen wird , die Ausführung wird fortgesetzt. Daher wird der Browser zu diesem Zeitpunkt blockiert. Wenn das Skript-Tag im Kopf platziert wird, kann der Benutzer nur eine leere Seite sehen, bevor die js-Datei geladen und ausgeführt wird. Diese Benutzererfahrung muss besonders schlecht sein. In diesem Zusammenhang werden häufig folgende Methoden verwendet:
Platzieren Sie alle Skript-Tags unten im Textkörper. Dadurch wird sichergestellt, dass die js-Datei und die Seite zuletzt geladen und ausgeführt werden kann den Benutzern zuerst angezeigt werden. Sie müssen jedoch zunächst wissen, ob die Darstellung der Seite auf dem ersten Bildschirm von einigen Ihrer js-Dateien abhängt. Wenn ja, müssen Sie diesen Teil der js-Datei auf den Kopf stellen.
Verwenden Sie „defer“, wie in der folgenden Schreibweise. Bei Verwendung von defer lädt der Browser zwar die entsprechende js-Datei herunter, wenn er das Tag analysiert, führt sie jedoch nicht sofort aus, sondern wartet, bis das DOM analysiert wird (vor DomContentLoader), bevor er diese js-Dateien ausführt. Daher wird der Browser nicht blockiert.
Dynamisches Laden von js-Dateien. Auf diese Weise können Sie den erforderlichen Code auch nach dem Laden laden Laden/On-Demand-Laden von js-Dateien: Es ist jetzt üblicher, dass Webpack Vue-Router/React-Router kombiniert, um das On-Demand-Laden zu implementieren. Die spezifische Methode lautet wie folgt:
1. Fügen Sie Skript-Tags dynamisch ein, um Skripte zu laden, z. B. durch den folgenden Code
<script src="test.js" type="text/javascript" defer></script>
2. Laden Sie JS-Dateien über xhr, aber durch Auf diese Weise können domänenübergreifende Probleme auftreten. Ein Beispiel ist wie folgt:
function loadScript(url, callback) { const script = document.createElement('script'); script.type = 'text/javascript'; // 处理IE if (script.readyState) { script.onreadystatechange = function () { if (script.readyState === 'loaded' || script.readyState === 'complete') { script.onreadystatechange = null; callback(); } } } else { // 处理其他浏览器的情况 script.onload = function () { callback(); } } script.src = url; document.body.append(script); } // 动态加载js loadScript('file.js', function () { console.log('加载完成'); })
3. Führen Sie mehrere js-Dateien zu einer zusammen und komprimieren Sie sie. Grund: Die meisten Browser unterstützen derzeit das parallele Herunterladen von JS-Dateien, es gibt jedoch immer noch eine gewisse Grenze für die Anzahl gleichzeitiger Downloads (je nach Browser können einige Browser nur 4 herunterladen), und für jede JS-Datei muss eine zusätzliche erstellt werden Mit einem Bei einer HTTP-Verbindung dauert das Laden von vier 25-KB-Dateien länger als das Laden einer 100-KB-Datei. Daher ist es für uns am besten, mehrere JS-Dateien zu einer zusammenzuführen und den Code zu komprimieren.
Wenn eine Funktion ausgeführt wird, wird ein Ausführungskontext generiert. Dieser Ausführungskontext definiert die Umgebung, in der die Funktion ausgeführt wird. Wenn die Funktion die Ausführung abschließt, wird der Ausführungskontext zerstört. Daher führt der mehrmalige Aufruf derselben Funktion zur Erstellung mehrerer Ausführungskontexte. Jeder Ausführungskontext verfügt über eine eigene Bereichskette. Ich glaube, jeder sollte den Bereich schon lange kennen. Der erste Bereich einer Funktion sind die Variablen innerhalb ihrer Funktion. Während der Funktionsausführung wird jedes Mal, wenn eine Variable angetroffen wird, die Bereichskette der Funktion durchsucht, um die erste passende Variable zu finden. Dabei wird zunächst nach Variablen innerhalb der Funktion gesucht und dann Schicht für Schicht entlang der Bereichskette durchsucht. Daher wenn wir auf die äußersten Variablen (globale Variablen) zugreifen möchten, führt dies zu einem relativ großen Leistungsverlust im Vergleich zum direkten Zugriff auf die internen Variablen. Daher können wir häufig verwendete globale Variablenreferenzen in einer lokalen Variablen speichern .
const xhr = new XMLHttpRequest(); xhr.open('get', 'file.js'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) { const script = document.createElement('script'); script.type = 'text/javascript'; script.text = xhr.responseText; document.body.append(script); } } }
In JavaScript wird es hauptsächlich in vier Typen unterteilt: Literale, lokale Variablen, Array-Elemente und Objekte. Der Zugriff auf Literale und lokale Variablen ist am schnellsten, während der Zugriff auf Array-Elemente und Objektmitglieder relativ langsam ist. Beim Zugriff auf Objektmitglieder wird, genau wie bei der Bereichskette, die Suche in der Prototypenkette (Prototyp) durchgeführt. Wenn sich das gesuchte Mitglied zu tief in der Prototypenkette befindet, ist die Zugriffsgeschwindigkeit daher langsamer. Daher sollten wir die Anzahl der Suchvorgänge und die Verschachtelungstiefe von Objektmitgliedern so weit wie möglich reduzieren . Beispielsweise minimiert der folgende Code
const a = 5; function outter () { const a = 2; function inner () { const b = 2; console.log(b); // 2 console.log(a); // 2 } inner(); }
die Anzahl der DOM-Operationen, verwendet JavaScript, um sie so weit wie möglich zu verarbeiten, und verwendet dazu lokale Variablen Speichern Sie so viele DOM-Knoten wie möglich. Zum Beispiel der folgende Code:
// 进行两次对象成员查找 function hasEitherClass(element, className1, className2) { return element.className === className1 || element.className === className2; } // 优化,如果该变量不会改变,则可以使用局部变量保存查找的内容 function hasEitherClass(element, className1, className2) { const currentClassName = element.className; return currentClassName === className1 || currentClassName === className2; }
Neuanordnung und Neuzeichnung so weit wie möglich reduzieren. Neuanordnung und Neuzusammenführung können sehr teuer sein Um die Neuanordnung zu reduzieren, können wir daher die folgenden Optimierungen vornehmen, um die Anzahl der Neuzusammenführungen zu eliminieren: 1. Wenn wir den Stil des Doms ändern möchten, sollten wir alle Änderungen so weit wie möglich zusammenführen und vornehmen sie einmal verarbeiten, um die Zahl der Neuordnungen und Weiterverweisungen zu reduzieren.
// 优化前 const el = document.getElementById('test'); el.style.borderLeft = '1px'; el.style.borderRight = '2px'; el.style.padding = '5px'; // 优化后,一次性修改样式,这样可以将三次重排减少到一次重排 const el = document.getElementById('test'); el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'
2.当我们要批量修改DOM节点的时候,我们可以将DOM节点隐藏掉,然后进行一系列的修改操作,之后再将其设置为可见,这样就可以最多只进行两次重排。具体的方法如下:
// 未优化前 const ele = document.getElementById('test'); // 一系列dom修改操作 // 优化方案一,将要修改的节点设置为不显示,之后对它进行修改,修改完成后再显示该节点,从而只需要两次重排 const ele = document.getElementById('test'); ele.style.display = 'none'; // 一系列dom修改操作 ele.style.display = 'block'; // 优化方案二,首先创建一个文档片段(documentFragment),然后对该片段进行修改,之后将文档片段插入到文档中,只有最后将文档片段插入文档的时候会引起重排,因此只会触发一次重排。。 const fragment = document.createDocumentFragment(); const ele = document.getElementById('test'); // 一系列dom修改操作 ele.appendChild(fragment);
3.使用事件委托:事件委托就是将目标节点的事件移到父节点来处理,由于浏览器冒泡的特点,当目标节点触发了该事件的时候,父节点也会触发该事件。因此,由父节点来负责监听和处理该事件。
那么,它的优点在哪里呢?假设你有一个列表,里面每一个列表项都需要绑定相同的事件,而这个列表可能会频繁的插入和删除。如果按照平常的方法,你只能给每一个列表项都绑定一个事件处理器,并且,每当插入新的列表项的时候,你也需要为新的列表项注册新的事件处理器。这样的话,如果列表项很大的话,就会导致有特别多的事件处理器,造成极大的性能问题。而通过事件委托,我们只需要在列表项的父节点监听这个事件,由它来统一处理就可以了。这样,对于新增的列表项也不需要做额外的处理。而且事件委托的用法其实也很简单:
function handleClick(target) { // 点击列表项的处理事件 } function delegate (e) { // 判断目标对象是否为列表项 if (e.target.nodeName === 'LI') { handleClick(e.target); } } const parent = document.getElementById('parent'); parent.addEventListener('click', delegate);
Das obige ist der detaillierte Inhalt vonEinführung in Methoden zur JavaScript-Leistungsoptimierung (mit Beispielen). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!