Javascript-Leistungsmessung

Das Messen der Zeit, die zum Ausführen einer Funktion benötigt wird, ist ein guter Beweis dafür, dass eine Implementierung eines Mechanismus produktiver ist als eine andere. Auf diese Weise können Sie sicherstellen, dass die Leistung der Funktion nach einigen Änderungen am Code nicht beeinträchtigt wurde. Es ist auch hilfreich, nach Engpässen bei der Anwendungsleistung zu suchen.

Wenn ein Webprojekt eine hohe Leistung aufweist, trägt dies zu seiner positiven Wahrnehmung durch die Benutzer bei. Und wenn Benutzer gerne mit der Ressource arbeiten, haben sie die Eigenschaft, zurückzukehren. Zum Beispiel in diesemDie Studie ergab, dass 88% der Online-Kunden weniger wahrscheinlich zu Ressourcen zurückkehren, auf die sie mit Unannehmlichkeiten stoßen. Diese Unannehmlichkeiten können durchaus durch Leistungsprobleme verursacht werden.

Aus diesem Grund sind Tools zur Ermittlung von Leistungsengpässen und zur Messung der Ergebnisse von Codeverbesserungen in der Webentwicklung wichtig. Solche Tools sind besonders relevant in der JavaScript-Entwicklung. Es ist wichtig zu wissen, dass jede Zeile JavaScript-Code möglicherweise das DOM blockieren kann, da JavaScript eine Single-Threaded-Sprache ist. In diesem Artikel werde ich darüber sprechen, wie die Leistung von Funktionen gemessen wird und was mit den Messergebnissen zu tun ist.





Wenn Sie der Meinung sind, dass einige Berechnungen zu umfangreich sind, um im Hauptthread ausgeführt zu werden, können Sie sie an einen Service Worker oder Web Worker verschieben.

Performance.now () -Methode


Die Performance- Schnittstelle ermöglicht über eine Methode den Zugriff auf einen Wert vom Typ DOMHighResTimeStampperformance.now() . Diese Methode gibt einen Zeitstempel zurück, der die Zeit in Millisekunden angibt, die seit Beginn des Dokuments vergangen ist. Darüber hinaus beträgt die Genauigkeit dieses Indikators etwa 5 Mikrosekunden (Bruchteile einer Millisekunde).

Um die Leistung eines Codefragments mithilfe der Methode zu messen performance.now(), müssen Sie zwei Zeitmessungen durchführen, die Ergebnisse dieser Messungen in Variablen speichern und dann die Ergebnisse der ersten von den Ergebnissen der zweiten Messung subtrahieren:

const t0 = performance.now();
for (let i = 0; i < array.length; i++) 
{
  // - 
}
const t1 = performance.now();
console.log(t1 - t0, 'milliseconds');

In Chrome können Sie nach dem Ausführen dieses Codes Folgendes erhalten:

0.6350000001020817 "milliseconds"

In Firefox wie folgt:

1 milliseconds

Wie Sie sehen können, sind die Messergebnisse in verschiedenen Browsern sehr unterschiedlich. Tatsache ist, dass in Firefox 60 die Genauigkeit der von der Leistungs-API zurückgegebenen Ergebnisse verringert wird. Wir werden mehr darüber reden.

Die Performance-Oberfläche bietet viel mehr Funktionen als nur die Rückgabe eines bestimmten Zeitstempels. Dazu gehört das Messen verschiedener Leistungsaspekte, die durch Erweiterungen dieser Schnittstelle wie die Performance Timeline- API , das Navigations-Timing , das User-Timing und das Resource-Timing dargestellt werden . Hier finden Sie das Material, um mehr über diese APIs zu erfahren.

In unserem Fall geht es darum, die Leistung von Funktionen zu messen, damit wir genügend Möglichkeiten haben, die die Methode bietetperformance.now().

Date.now () und performance.now ()


Hier haben Sie vielleicht den Gedanken, dass Sie die Methode verwenden können, um die Leistung zu messen Date.now(). Dies ist zwar möglich, aber dieser Ansatz hat Nachteile.

Die Methode Date.now()gibt die seit der Unix-Ära (1970-01-01T00: 00: 00Z) verstrichene Zeit in Millisekunden zurück und hängt von der Systemuhr ab. Dies bedeutet nicht nur, dass diese Methode nicht so genau ist wie performance.now(), sondern dass sie im Gegensatz dazu performance.now()Werte zurückgibt, die unter bestimmten Bedingungen auf falschen Taktanzeigen basieren können. Rich Gentlekor, ein Programmierer, der mit der WebKit-Engine verwandt ist, sagt Folgendes: „Vielleicht glauben Programmierer weniger, dass Messwerte beim Zugriff zurückgegeben werdenDateAufgrund der Systemzeit ist es absolut unmöglich, das Ideal für die Überwachung realer Anwendungen aufzurufen. Die meisten Systeme verfügen über einen Daemon, der die Zeit regelmäßig synchronisiert. Das Einstellen der Systemuhr für einige Millisekunden alle 15 bis 20 Minuten ist üblich. Bei einer solchen Frequenz sind die Takteinstellungen von etwa 1% der Messungen in Intervallen von 10 Sekunden ungenau. "

Console.time () -Methode


Die Zeitmessung mit dieser API ist äußerst einfach. Genug, rufen Sie vor dem Code, dessen Leistung Sie auswerten müssen, die Methode console.time()und nach diesem Code die Methode auf console.timeEnd(). In diesem Fall müssen die eine und die andere Methode dasselbe Zeichenfolgenargument übergeben. Auf einer Seite können bis zu 10.000 solcher Timer gleichzeitig verwendet werden.

Die Genauigkeit von Zeitmessungen, die mit dieser API durchgeführt werden, ist dieselbe wie bei Verwendung der Leistungs-API, aber die Genauigkeit, die in jeder spezifischen Situation erreicht wird, hängt vom Browser ab.

console.time('test');
for (let i = 0; i < array.length; i++) {
  // - 
}
console.timeEnd('test');

Nach der Ausführung dieses Codes gibt das System automatisch Informationen über die verstrichene Zeit an die Konsole aus.

In Chrome sieht es ungefähr so ​​aus:

test: 0.766845703125ms

In Firefox wie folgt:

test: 2ms - timer ended

Tatsächlich ist hier alles sehr ähnlich zu dem, was wir bei der Arbeit gesehen haben performance.now().

Die Stärke der Methode console.time()liegt in ihrer Benutzerfreundlichkeit. Wir sprechen nämlich von der Tatsache, dass für seine Anwendung keine Deklaration von Hilfsvariablen erforderlich ist und der Unterschied zwischen den darin aufgezeichneten Indikatoren festgestellt werden muss.

Reduzierte Zeitgenauigkeit


Wenn Sie mit den oben beschriebenen Tools die Leistung Ihres Codes in verschiedenen Browsern gemessen haben, können Sie darauf achten, dass die Messergebnisse variieren können.

Der Grund dafür ist , dass Browser - Benutzer versuchen , davor zu schützen , zeitbasierten Angriffe und von Browser - Identifikation Mechanismen ( Browser - Fingerprinting ). Wenn sich die Ergebnisse der Zeitmessung als zu genau herausstellen, kann dies Angreifern beispielsweise die Möglichkeit geben, Benutzer zu identifizieren.

In Firefox 60 wird, wie bereits erwähnt, die Genauigkeit der Zeitmessergebnisse verringert . Dies erfolgt durch Setzen des Eigenschaftswerts privacy.reduceTimerPrecisionauf 2 ms.

Beachten Sie dies beim Testen der Leistung


Jetzt stehen Ihnen Tools zur Verfügung, mit denen Sie die Leistung von JavaScript-Funktionen messen können. Bevor Sie jedoch zur Sache kommen, müssen Sie einige der Funktionen berücksichtigen, über die wir jetzt sprechen werden.

▍ Teilen und erobern


Angenommen, Sie haben beim Filtern einiger Daten auf den langsamen Betrieb der Anwendung geachtet. Sie wissen jedoch nicht genau, wo der Leistungsengpass liegt.

Anstatt zu spekulieren, welcher Teil des Codes langsam ausgeführt wird, ist es besser, dies mit den oben genannten Methoden herauszufinden.

Um ein allgemeines Bild des Geschehens zu erhalten, müssen Sie zunächst die Leistung des Codeblocks verwenden console.time()und console.timeEnd()bewerten, was sich vermutlich negativ auf die Leistung auswirkt. Dann müssen Sie die Geschwindigkeit der einzelnen Teile dieses Blocks betrachten. Wenn einer von ihnen merklich langsamer aussieht als die anderen, müssen Sie ihm besondere Aufmerksamkeit schenken und ihn analysieren.

Je weniger Code zwischen Aufrufen von Methoden zur Zeitmessung vorhanden ist, desto geringer ist die Wahrscheinlichkeit, dass etwas gemessen wird, das für die Problemsituation nicht relevant ist.

▍ Berücksichtigen Sie die Merkmale des Verhaltens von Funktionen bei verschiedenen Eingabewerten


In realen Anwendungen können die am Eingang einer bestimmten Funktion empfangenen Daten sehr unterschiedlich sein. Wenn Sie die Leistung einer Funktion messen, der ein zufällig ausgewählter Datensatz übergeben wurde, liefert dies keine wertvollen Informationen, die klarstellen können, was passiert.

Funktionen bei der Untersuchung der Leistung müssen mit Eingabedaten aufgerufen werden, die so real wie möglich sind.

▍ Führen Sie Funktionen mehrmals aus


Angenommen, Sie haben eine Funktion, die über ein Array iteriert. Sie führt einige Berechnungen mit jedem Element des Arrays durch und gibt danach ein neues Array mit den Ergebnissen der Berechnungen zurück. Wenn Sie über die Optimierung dieser Funktion nachdenken, möchten Sie wissen, was in Ihrer Situation schneller funktioniert - eine Schleife forEachoder eine reguläre Schleife for.

Hier sind zwei Optionen für diese Funktion:

function testForEach(x) {
  console.time('test-forEach');
  const res = [];
  x.forEach((value, index) => {
    res.push(value / 1.2 * 0.1);
  });

  console.timeEnd('test-forEach')
  return res;
}

function testFor(x) {
  console.time('test-for');
  const res = [];
  for (let i = 0; i < x.length; i ++) {
    res.push(x[i] / 1.2 * 0.1);
  }

  console.timeEnd('test-for')
  return res;
}

Testen Sie die Funktionen:

const x = new Array(100000).fill(Math.random());
testForEach(x);
testFor(x);

Nach dem Ausführen des Codes erhalten wir die folgenden Ergebnisse:

test-forEach: 27ms - timer ended
test-for: 3ms - timer ended

Der Zyklus schien forEachviel langsamer zu sein als der Zyklus for. Immerhin zeigen die Testergebnisse genau das?

Tatsächlich ist es nach einem einzigen Test zu früh, um solche Schlussfolgerungen zu ziehen. Versuchen wir, die Funktionen zweimal aufzurufen:

testForEach(x);
testForEach(x);
testFor(x);
testFor(x);

Wir bekommen folgendes:

test-forEach: 13ms - timer ended
test-forEach: 2ms - timer ended
test-for: 1ms - timer ended
test-for: 3ms - timer ended

Es stellt sich heraus, dass die Funktion, in der es verwendet wird forEach, das zweite Mal genannt wird, genauso schnell ist wie die, in der es verwendet wird for. Angesichts der Tatsache, dass die ersten forEachFunktionsaufrufe jedoch viel langsamer arbeiten, lohnt es sich möglicherweise immer noch nicht, sie zu verwenden.

▍Testleistung in verschiedenen Browsern


Die obigen Tests wurden in Firefox durchgeführt. Aber was ist, wenn Sie sie in Chrome ausführen? Die Ergebnisse werden völlig anders sein:

test-forEach: 6.156005859375ms
test-forEach: 8.01416015625ms
test-for: 4.371337890625ms
test-for: 4.31298828125ms

Tatsache ist, dass die Browser Chrome und Firefox auf unterschiedlichen JavaScript-Engines basieren, die unterschiedliche Leistungsoptimierungen implementieren. Es ist sehr nützlich, diese Unterschiede zu kennen.

In diesem Fall bietet Firefox eine bessere Optimierung forEachmit ähnlichen Eingaben. Und der Zyklus forist schneller als forEachin Chrome und Firefox. Infolgedessen ist es wahrscheinlich besser, sich mit der Variante der Funktion c zu befassen for.

Dies ist ein gutes Beispiel dafür, wie wichtig es ist, die Leistung in verschiedenen Browsern zu messen. Wenn Sie die Leistung eines Codes nur in Chrome bewerten, können Sie zu dem Schluss kommen, dass der Zyklus forEachim Vergleich zum Zyklus fornicht so schlecht ist.

▍ Wenden Sie künstliche Grenzen auf Systemressourcen an


Die in unseren Experimenten erhaltenen Werte sehen nicht besonders groß aus. Beachten Sie jedoch, dass Computer, die für die Entwicklung verwendet werden, normalerweise viel schneller sind als beispielsweise das durchschnittliche Mobiltelefon, auf dem sie im Internet surfen.

Verwenden Sie die Funktionen des Browsers, um die Systemressourcen künstlich zu begrenzen, um sich an die Stelle eines Benutzers zu setzen, der nicht über das schnellste Gerät verfügt. Zum Beispiel - um die Prozessorleistung zu reduzieren.

Mit diesem Ansatz können 10 oder 50 Millisekunden leicht zu 500 werden.

▍ Messen Sie die relative Leistung


Leistungsmessungen hängen normalerweise nicht nur von der Hardware ab, sondern auch von der aktuellen Prozessorlast und von der Arbeitslast des Hauptthreads der JavaScript-Anwendung. Versuchen Sie daher, sich auf relative Indikatoren zu verlassen, die die Leistungsänderung charakterisieren, da die absoluten Indikatoren, die bei der Analyse desselben Codefragments zu unterschiedlichen Zeiten erhalten werden, stark variieren können.

Zusammenfassung


In diesem Artikel haben wir uns einige JavaScript-APIs angesehen, mit denen die Leistung gemessen werden kann. Wir haben darüber gesprochen, wie man sie zur Analyse von echtem Code verwendet. Ich glaube, dass es am einfachsten ist, einige einfache Messungen durchzuführen console.time().

Ich habe das Gefühl, dass viele Front-End-Entwickler der Messung der Leistung ihrer Projekte nicht genügend Aufmerksamkeit schenken. Und sie sollten die relevanten Indikatoren ständig überwachen, da die Produktivität den Erfolg und die Rentabilität von Projekten beeinflusst.

Liebe Leser! Wenn Sie die Leistung Ihrer Projekte ständig überwachen, teilen Sie uns bitte mit, wie Sie dies tun.


All Articles